什么是单点登录

网站一:人事系统 https://ehr.jxnu.edu.cn/
网站二:OA办公系统 https://oas.jxnu.edu.cn/
  两个网站域名不同,但是它们属于同一单位。当你在某一个网站登录输入完密码之后,你再去访问第二个网站时,就不需要再次输入密码了,可以直接显示登录状态,从而提高办公效率。
  主要是通过CAS认证中心 https://uis.jxnu.edu.cn/cas/login 登录后即可实现多系统互通登录

SSO Demo例子如下:有sitea系统、siteb系统、cas系统

sitea系统

#coding: utf8                                                                                                               
import os
from datetime import timedelta
from flask import Flask, session, redirect, url_for, request
import urllib
 
app = Flask(__name__)
 
app.secret_key = 'b123456'
app.permanent_session_lifetime = timedelta(seconds=24 * 60 * 60) 
 
@app.route('/')
def index():
    #表示存活期为浏览器进程的存活期
    session.permanent = False
    ticket = request.args.get('ticket', None)
    #此处应该验证ticket是认证中心发布的
    if ticket is not None:
        session['name'] = ticket.strip()
    #检测登录态
    if 'name' in session:
        return 'sitea站点登录成功'
    else:
        referer = urllib.parse.quote('http://test-sso-sitea.wanlf.vip:5201/')
        #test-sso-cas.wanlf.vip:5200  cas域名加端口设置,若做了反向代理即可不加端口      
        return redirect('http://test-sso-cas.wanlf.vip:5200/login?referer=' + referer)
 
if __name__ == '__main__':
    app.run(
        host="0.0.0.0",
        port=int("5201"),
        debug=True
    ) 

siteb系统

#coding: utf8                                                                                                               
import os
from datetime import timedelta
from flask import Flask, session, redirect, url_for, request
import urllib
 
app = Flask(__name__)
 
app.secret_key = 'a123456'
app.permanent_session_lifetime = timedelta(seconds=24 * 60 * 60) 
 
@app.route('/')
def index():
    #表示存活期为浏览器进程的存活期
    session.permanent = False
    ticket = request.args.get('ticket', None)
    print(session)
    if ticket is not None:
        session['name'] = ticket.strip()
    #检测登录态
    if 'name' in session:
        print(session['name'])
        return 'siteb站点登录成功'
    else:
        referer = urllib.parse.quote('http://test-sso-siteb.wanlf.vip:5202/')
        #test-sso-cas.wanlf.vip:5200  cas端域名加端口设置,若做了反向代理即可不加端口      
        return redirect('http://test-sso-cas.wanlf.vip:5200/login?referer=' + referer)
 
if __name__ == '__main__':
    app.run(
        host="0.0.0.0",
        port=5202,
        debug=True
)

cas认证系统

#coding: utf8                                                                                                               
import os
from datetime import timedelta
from flask import Flask, session, render_template, request, redirect
import urllib
 
app = Flask(__name__)
 
app.secret_key = '123456'
app.permanent_session_lifetime = timedelta(seconds=30 * 24 * 60 * 60) 
 
@app.route('/login')
def login():
    session.permanent = True
    referer = request.args.get('referer', None)
    if referer is not None:
        referer = referer.strip()
 
    if 'name' in session:
        if referer is not None:
            return redirect(referer + '?ticket=' + _makeTicket())
    return render_template('login.html', **dict(referer=referer))
 
@app.route('/dologin',methods=['POST'])
def doLogin():
    ''' 
    这里没有真正的去进行验证,直接写session了,然后redirect了
    '''
    session.permanent = True
    print(request.args)
    print(request.form)
    referer = request.args.get('referer', None)
    if(request.form.get('username')== 'zhangsan') and (request.form.get('password')=='111111'):
        print("username and password is right")
    else:
        return "username and passwprd is not right"
 
    
    if referer is not None:
        referer = urllib.parse.unquote(referer.strip())
    #不实现登录功能,直接设置登录态
    _setLoginState()
    if referer:
        return redirect(referer + '?ticket=' + _makeTicket())
    else:
        return 'error'
 
def _setLoginState():
    session['name'] = 'zhangsan'
 
def _makeTicket():
    '''生成ticket,这里只是简单返回用户名,真实场景中可以使用des之类的加密算法'''
    return 'zhangsan'
 
if __name__ == '__main__':
    app.run(
        host="0.0.0.0",
        port=int("5200"),
        debug=True
    )                 

login页面

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>SSO</title>
  <meta name="author" content="" />
  <meta http-equiv="X-UA-Compatible" content="IE=7" />
  <meta name="keywords" content="SSO" />
  <meta name="description" content="SSO" />
</head>
<link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css">
<!--使用Bootstrap的js插件,必须先调入jQuery-->
<script src="http://libs.baidu.com/jquery/1.9.0/jquery.min.js"></script>

<!-- 包括所有bootstrap的js插件或者可以根据需要使用的js插件调用 -->
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>

<body>
  <form method="POST" action="dologin?referer={{ referer }}">

    <div class="input-group" style="width: 500px;margin: 0 auto;margin-top: 50px">
      <span class="input-group-addon" id="basic-addon1">账号</span>
      <input type="text" class="form-control" placeholder="zhangsan" name="username" aria-describedby="basic-addon1">
    </div>
    <div class="input-group" style="width: 500px;margin: 0 auto;margin-top: 10px">
      <span class="input-group-addon" id="basic-addon1">密码</span>
      <input type="text" class="form-control" placeholder="111111" name="password" aria-describedby="basic-addon1">
    </div>

    <div style="width: 100px;margin: 0 auto;margin-top: 10px">
      <button type="submit" class="btn btn-default">提交</button>
    </div>

</body>

</html>

分别启动sitea系统、siteb系统、cas认证系统

nohup python sitea.py > nohup.out 2>&1 &
nohup python siteb.py > nohup.out 2>&1 &
nohup python sso.py > nohup.out 2>&1 &

系统a访问跳转至cas系统

输入a系统地址: http://test-sso-sitea.wanlf.vip:5201/
跳转至cas登录中心:http://test-sso-cas.wanlf.vip:5200/login?referer=http%3A//test-sso-sitea.wanlf.vip%3A5201/
image
登录成功后会携带ticket票据返回a系统
image-1670414757078
此时输入b系统访问地址:http://test-sso-sitea.wanlf.vip:5202/
b系统未输入账号密码也显示已登录
image-1670414890354
清除浏览器cookie即可重新测试
image-1670415182930

sso-demo代码

wget http://files.wanlf.vip/usr/local/flask/flask-sso-demo.tar.gz