python flask 实现多域名网站简单的 sso 功能

liftword3周前 (05-04)技术文章10

1.什么是单点登录

所谓单点登录,你可以简单的理解为有两个网站,这个两个网站的域名是不相同,但是它们同属于一家公司。当你在某一个网站登录输入完密码之后,你再去访问第二个网站时,就不需要再次输入密码了,可以直接显示登录状态。例如你在百度文库登录之后,再去百度知道,你发现也同样处于登录状态。

2.单点登录原理

单点登录最重要的是认证中心,假设有a网站和b网站,当你登录其中任何一个时,都会跳转到认证中心,实际的用户名和密码的验证是在这里完成的。

2.1认证中心如何区分子系统

登录时,都跳转到认证中心,那么认证中心怎么区分这次请求是从哪个网站来的呢?方法很简单,你登录a网站时,a网站的后台跳转到认证中心时,会将自己网站的网址作为参数(referer),这样,认证中心就知道是哪个子系统网站在登录了。

2.2认证中心登录后做什么

你在认证中心填写好用户名和密码登录后,认证中心会再次跳转到a网站,而且要带上一个ticket,这个很关键,同时设置session

2.3 a网站怎么办

对于a网站,请求里带有ticket,那么就对这个ticket进行验证,看他是不是认证中心颁发的(我的程序没有做这个验证),如果是呢,则登录成功

2.4 b网站如何登录

a网站登录后,你又想去b网站逛逛,和a网站一样,也要跳转到认证中心,可是不同于第一次跳转,在2.2中,已经设置了session,就说明已经在认证中心认证过了,所以认证中心这次会直接跳转到b网站,也带着ticket,b网站看到ticket,也去验证是否是认证中心颁发的,最后b网站成功登录。

3 代码构建

项目结构如下所示,项目使用的框架是python flask。

3.1 login.html

<!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>
<body>
<form method="POST" action="dologin?referer={{ referer }}">
 
account:  <input type="username" name="username"><br>
password: <input type="password" name="password"><br>
 
<input type="submit" value="logon">
</body>
</html>

3.2 sso.py

#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.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
    )                 

3.3 a.py

#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 'a登录成功'
    else:
        referer = urllib.quote('http://www.a.com:5201/')
        return redirect('http://www.sso.com:5200/login?referer=' + referer)
 
if __name__ == '__main__':
    app.run(
        host="0.0.0.0",
        port=int("5201"),
        debug=True
    ) 

3.4 b.py

#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 'b登录成功'
    else:
        referer = urllib.quote('http://www.b.com:5202/')
        return redirect('http://www.sso.com:5200/login?referer=' + referer)
 
if __name__ == '__main__':
    app.run(
        host="0.0.0.0",
        port=5202,
        debug=True
)

注意:代码构建完成之后需要在window的hosts文件或者服务器的hosts文件中添加域名和ip的映射。

4.结果演示

首先在浏览器中输入http://www.a.com:5201,可以看到自动跳转到了http://www.sso.com:5200,并且调用了login接口

这个时候输入账号密码zhangsan/111111,会发现调用了dologin接口,并且带上了a网站的域名作为参数,验证通过后重新跳转到了www.a.com网站,并带上了ticket参数,并且显示了a网站登录成功的结果。


这个时候再去登录www.b.com,会发现,会先去www.sso.com认证一下,发现session已经存在之后,就会跳回www.b.com,并且设置session。所以在没有输入密码的情况下,b网站也成功登录。

相关文章

如何用Python搭建自己的网站(python 搭建网站)

看看如何使用Python工具搭建自己的网站吧,使用Python开发网站通常需要以下几步:搭建步骤选择Web框架:Python有许多Web框架可供选择,如Django、Flask等。选择适合自己的框架非...

Python + Flet 开发网站的最佳数据库模块组合

对于使用 Python 和 Flet 开发网站并需要数据库支持的应用,以下是推荐的模块组合方案。方案一:SQLite + SQLAlchemy (推荐轻量级方案)**适用场景**:中小型应用、单用户或...

让我们用 Flask + Python 构建一个漂亮简约的网站(附完整源码)

正如大多数人所知,Python 是一种非常棒的编程语言,具有大量的功能,您可以使用 Python 做的事情之一就是开发网站,所以让我们用 Flask 构建一个简约的网站吧!现在,这个网站已经完全建成并...

使用 Python、FastHTML 和 Uvicorn 构建简单的博客网站

FastHTML 是2024 年 7 月推出的 Python Web 框架,是一个简单但功能强大的框架,允许开发人员使用纯 Python 构建 Web 应用程序。 (不需要复杂的模板引擎)。 Fast...

想用 Python 做网站?来了解下 Flask!

Python Flask是一种轻量级的Web应用程序框架,它使用Python编程语言开发。它提供了一种简单的方法来构建Web应用程序,并且可以轻松地与其他Python库集成。它是一种灵活、可扩展的框架...

Python Web开发实战教程--简介(python web开发基础教程)

一、简介A. Python作为网站开发语言的优势Python是一种简单易学、功能强大且广受欢迎的编程语言,它在Web开发领域中得到了广泛的应用。Python语言的优势包括:1. 易于学习和使用:Pyt...