什么是单点登录
网站一:人事系统 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/
登录成功后会携带ticket票据返回a系统
此时输入b系统访问地址:http://test-sso-sitea.wanlf.vip:5202/
b系统未输入账号密码也显示已登录
清除浏览器cookie即可重新测试
sso-demo代码
wget http://files.wanlf.vip/usr/local/flask/flask-sso-demo.tar.gz