SSO简介

单点登录(Single Sign On)功能是一个非常常用的功能,尤其是我们在多个系统之间需要登录同步的时候,例如我们在登录QQ空间后,再去QQ的其他网站,都是默认登录的状态,这就是单点登录。

单点登录有很多种实现方法,这里介绍一个通过共享session的实现方法。实现共享session要做的就是要让多个不同应用共用同一个session,但是session默认的是每个应用一个独立的session和cookie的,所以这里要对session的存储进行配置。

除了默认的session存储,我也可以设置让session存储在文件、缓存或者数据库中。

如果我们让session存储在一个固定位置或者数据库中,然后我们设置各个应用cookie的domain为父域地址即可实现各个cookie的相同,从而时候各个cookie中存储的sessionID一致。

搭建测试环境

下面我们来创建两个空的Django项目来进行演示,SSO1和SSO2,这里采用pycharm直接创建两个Django项目,也可以在命令行中使用django-admin startproject sso来创建,其中sso是创建的项目名称。这里也可以使用两个完全相同的项目,在不同地址启动,但是为了演示效果,这里创建了2个。

创建好两个项目后,我们要给项目写一个模拟的登录,注销的功能。

templates文件夹下创建文件login.html文件。这里直接使用之前写过的登录页面的代码,样式就不加了,在SSO1和SSO2中都加入login.html,具体代码为:

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body><div class="login_content">    <div class="page-header" id="page_header">      <h1>登录<small>Login</small></h1>    </div>    <div id="login_form">        <form method="post">          <div class="form-group">            <label for="exampleInputEmail1">Email address</label>            <input type="input" class="form-control" name="usr" id="exampleInputEmail1" placeholder="username">          </div>          <div class="form-group">            <label for="exampleInputPassword1">密码</label>            <input type="password" class="form-control" name="password" id="exampleInputPassword1" placeholder="密码">          </div>          <div id="login_butt">              <button type="submit" class="btn btn-default">登录</button>              <button type="button" class="btn btn-default" onclick="">注册</button>          </div>        </form>    </div></div></body></html>

然后在SSO1文件夹创建一个view.py文件,用来存放视图函数。(这里仅为演示SSO,就不分模块了。)

创建文件后的文件目录为:(SSO2项目一样)

.├── SSO1│   ├── __init__.py│   ├── asgi.py│   ├── settings.py│   ├── urls.py│   ├── view.py│   └── wsgi.py├── manage.py├── templates│   └── login.html└── venv    ├── bin    ├── include    ├── lib    └── pyvenv.cfg

插入一个小BUG

macbook运行环境,pycharm创建的Django应用有时候初始化有个bug,缺少os库,会报错:

Traceback (most recent call last):  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/manage.py", line 22, in <module>    main()  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/manage.py", line 18, in main    execute_from_command_line(sys.argv)  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line    utility.execute()  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/core/management/__init__.py", line 345, in execute    settings.INSTALLED_APPS  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/conf/__init__.py", line 82, in __getattr__    self._setup(name)  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/conf/__init__.py", line 69, in _setup    self._wrapped = Settings(settings_module)  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/venv/lib/python3.7/site-packages/django/conf/__init__.py", line 170, in __init__    mod = importlib.import_module(self.SETTINGS_MODULE)  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module    return _bootstrap._gcd_import(name[level:], package, level)  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import  File "<frozen importlib._bootstrap>", line 983, in _find_and_load  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked  File "<frozen importlib._bootstrap_external>", line 728, in exec_module  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed  File "/Users/qiguan/Documents/develop_files/python_files/SSO1/SSO1/settings.py", line 57, in <module>    'DIRS': [os.path.join(BASE_DIR, 'templates')]NameError: name 'os' is not defined

如果有这个报错的话,在setting.py中导入os即可:import os


然后我们在两个项目的view.py中写入登录和注销函数:

from django.http import HttpResponsefrom django.shortcuts import render, redirectdef login(request):    if request.method == 'GET':        if 'usr' in request.session:            # 如果session中已有信息,则显示            usr = request.session['usr']            password = request.session['password']            return HttpResponse("usr:{},password:{},sessionid:{},cookie:{}".format(usr,password,request.session.session_key,request.COOKIES))        return render(request,'login.html')    if request.method == 'POST':        usr = request.POST['usr']        password = request.POST['password']        request.session['usr'] = usr        request.session['password'] = password        return HttpResponse(            "usr:{},password:{},sessionid:{},cookie:{}".format(usr, password, request.session.session_key,                                                               request.COOKIES))def logout(request):    request.session.clear()    return redirect('/login')

url.py中添加路由信息:

"""SSO1 URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:    https://docs.djangoproject.com/en/3.1/topics/http/urls/Examples:Function views    1. Add an import:  from my_app import views    2. Add a URL to urlpatterns:  path('', views.home, name='home')Class-based views    1. Add an import:  from other_app.views import Home    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')Including another URLconf    1. Import the include() function: from django.urls import include, path    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))"""from django.contrib import adminfrom django.urls import pathfrom . import viewurlpatterns = [    path('admin/', admin.site.urls),    path('login/',view.login),    path('logout/',view.logout),]

Django默认配置了csrf,需要将它注释掉,在settings.py文件中搜csrf,然后注释掉。

修改后的settings.py文件为:

"""Django settings for SSO1 project.
Generated by 'django-admin startproject' using Django 3.1.7.
For more information on this file, seehttps://docs.djangoproject.com/en/3.1/topics/settings/
For the full list of settings and their values, seehttps://docs.djangoproject.com/en/3.1/ref/settings/"""
from pathlib import Pathimport os
# Build paths inside the project like this: BASE_DIR / 'subdir'.BASE_DIR = Path(__file__).resolve().parent.parent# Quick-start development settings - unsuitable for production# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!SECRET_KEY = 'o=blc^vzeb1&g*b!si(wtxe44_=i5cv(3jqm2*u2u&7vgj%&=%'
# SECURITY WARNING: don't run with debug turned on in production!DEBUG = True
ALLOWED_HOSTS = []# Application definition
INSTALLED_APPS = [    'django.contrib.admin',    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions',    'django.contrib.messages',    'django.contrib.staticfiles',]
MIDDLEWARE = [    'django.middleware.security.SecurityMiddleware',    'django.contrib.sessions.middleware.SessionMiddleware',    'django.middleware.common.CommonMiddleware',    # 'django.middleware.csrf.CsrfViewMiddleware',    'django.contrib.auth.middleware.AuthenticationMiddleware',    'django.contrib.messages.middleware.MessageMiddleware',    'django.middleware.clickjacking.XFrameOptionsMiddleware',]
ROOT_URLCONF = 'SSO1.urls'
TEMPLATES = [    {        'BACKEND': 'django.template.backends.django.DjangoTemplates',        'DIRS': [os.path.join(BASE_DIR, 'templates')]        ,        'APP_DIRS': True,        'OPTIONS': {            'context_processors': [                'django.template.context_processors.debug',                'django.template.context_processors.request',                'django.contrib.auth.context_processors.auth',                'django.contrib.messages.context_processors.messages',            ],        },    },]
WSGI_APPLICATION = 'SSO1.wsgi.application'# Database# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
DATABASES = {    'default': {        'ENGINE': 'django.db.backends.sqlite3',        'NAME': BASE_DIR / 'db.sqlite3',    }}# Password validation# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [    {        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',    },    {        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',    },    {        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',    },    {        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',    },]# Internationalization# https://docs.djangoproject.com/en/3.1/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True# Static files (CSS, JavaScript, Images)# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = '/static/'

然后分别为两个项目做数据库迁移,创建一些Django项目的基础库:

python3 manage.py migrate

两个项目都是同样的配置,这样我们目前两个测试的项目就搭建好了,然后我们分别启动他们在不同的端口。这里我们就直接手动启动了,分别启动在5000和6000端口。

python3 manage.py runserver 127.0.0.1:5000
python3 manage.py runserver 127.0.0.1:7000

启动两个项目:


现在我们分别在浏览器中打开http://127.0.0.1:5000/login/http://127.0.0.1:7000/login/,显示的页面都是登录页面,显示如下:

这时我们在http://127.0.0.1:5000/login/随意输入账户密码点击登录,显示:

usr:123,password:123,sessionid:None,cookie:{'csrftoken': '8YPzJbY03sHJUZH6kdFZzr9TkDtdVTKflgDDeIn0wgGC6cAeudcrkXLyIxXBEnzG'}

此时我们进入http://127.0.0.1:7000/login/,发现这个应用中,显示的还是之前的页面,登录没有同步。下面我们来实现我们的SSO,这里的实现方法非常的简单,这里提供2中实现方法:

  • 将session固定存储在同一个文件中,

  • 将session存储在Redis中

将session存储在同一个文件中实现SSO

我们在SSO2文件下创建了一个session文件夹,这个文件夹位置任意,写绝对路径即可。

然后我们在两个项目的settings.py中对cookie和session进行配置

# 设置cookie的domain为父域domain,# 如果是使用域名,以百度为例,主域名为`www.baidu.com`,旗下各个应用为:'asd.baidu.com'# 则这里设置为:`.baidu.com`SESSION_COOKIE_DOMAIN = '127.0.0.1'
# 设置session存储在文件中SESSION_ENGINE = 'django.contrib.sessions.backends.file'# 设置存储位置,这里设为绝对路径SESSION_FILE_PATH = '/Users/qiguan/Documents/develop_files/python_files/SSO2/session'

注意一下,这里配置的都是一样的,但是如果两个项目名称不一样的话,是不能直接将完整的settings.py直接复制到另一个的,因为里面有一些项目的配置,例如ROOT_URLCONF = 'SSO1.urls'WSGI_APPLICATION = 'SSO1.wsgi.application'这些前面的都是项目名,需要主要区分。

此时我们在打开http://127.0.0.1:5000/login/,输入账号密码,此页面显示:

usr:123,password:123,sessionid:2bs2nx2iq879epxu7au7o1zq63o095v7,cookie:{'sessionid': '2bs2nx2iq879epxu7au7o1zq63o095v7', 'csrftoken': '8YPzJbY03sHJUZH6kdFZzr9TkDtdVTKflgDDeIn0wgGC6cAeudcrkXLyIxXBEnzG'}

此时我们在打开http://127.0.0.1:7000/login/,我们直接访问,而不用登录,发现显示同样的内容,即我们使用的是同样的内容,实现了SSO。

使用Redis实现SSO

使用文件系统上实现共享session在小并发系统上不会出现问题,但是并发量大的话,会出现一些问题,所以我们这里再介绍一下使用Redis的实现。

需要自行安装Redis,并且在两个项目使用的Python中安装Django-redis:
pip3 install django-redis

在做好这些之后,修改settings.py文件,将使用文件存储session的配置注释掉,修改为:

# # 设置session存储在文件中# SESSION_ENGINE = 'django.contrib.sessions.backends.file'# # 设置存储位置,这里设为绝对路径# SESSION_FILE_PATH = '/Users/qiguan/Documents/develop_files/python_files/SSO2/session'
# 使用Redis存储sessionCACHES = {    "default": {        "BACKEND": "django_redis.cache.RedisCache",        "LOCATION": "redis://127.0.0.1:6379",        "OPTIONS": {            "CLIENT_CLASS": "django_redis.client.DefaultClient",            "CONNECTION_POOL_KWARGS": {"max_connections": 100}            # "PASSWORD": "123",        }    }}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'SESSION_CACHE_ALIAS = 'default'SESSION_COOKIE_AGE = 60 * 5

此时我们再来测试一下两个应用,这时我们先访问一下logout,将session清空,然后访问:http://127.0.0.1:5000/login/,输入账户密码后显示:

usr:123,password:123,sessionid:None,cookie:{'csrftoken': '8YPzJbY03sHJUZH6kdFZzr9TkDtdVTKflgDDeIn0wgGC6cAeudcrkXLyIxXBEnzG'}

此时我们访问http://127.0.0.1:7000/login/(不登录),显示同样的usr和password信息。

此时我们的SSO也可以正常实现。

好了,本文就先到这里,大家如有需要,可以根据具体的业务进行实现,这里就不赘述了。等以后有空再写一些Django相关的开发博客。

Django实现单点登录(SSO)相关推荐

  1. 基于.Net的单点登录(SSO)解决方案

    基于.Net的单点登录(SSO)解决方案 前些天一位朋友要我帮忙做一单点登录,其实这个概念早已耳熟能详,但实际应用很少,难得最近轻闲,于是决定通过本文来详细描述一个SSO解决方案,希望对大家有所帮助. ...

  2. PHP多台服务实现单点登录,如何在多台服务器上共享Session(PHP/JSP/ASP.NET)以及单点登录(SSO)...

    如何在多台服务器上共享Session(PHP/JSP/ASP.NET)以及单点登录(SSO) Apache Session复制: 使用Memcached来共享PHP Session: 使用Cohere ...

  3. jwt单点登录_单点登录SSO技术选型

    一些人存在的意义总归是让另一些人成长,然后消失. --刘同<谁的青春不迷茫> 1.单点登录是什么? 单点登录主要用于多系统集成,即在多个系统中,用户只需要到一个中央服务器登录一次即可访问这 ...

  4. OAuth2 实现单点登录 SSO

    转载自  OAuth2 实现单点登录 SSO 1. 前言 技术这东西吧,看别人写的好像很简单似的,到自己去写的时候就各种问题,"一看就会,一做就错".网上关于实现SSO的文章一大堆 ...

  5. 基于云端的通用权限管理系统,SAAS服务,基于SAAS的权限管理,基于SAAS的单点登录SSO,企业单点登录,企业系统监控,企业授权认证中心...

    基于云端的通用权限管理系统 SAAS服务 基于SAAS的权限管理 基于SAAS的单点登录SSO 基于.Net的SSO,单点登录系统,提供SAAS服务 基于Extjs 4.2 的企业信息管理系统 基于E ...

  6. 安全单点登录(SSO)解决方案

    随着企业大量采用云应用程序,最终用户不得不在一天中处理越来越多的密码,只是为了完成他们的工作.为了进行有效的用户身份管理,您需要采用一种有效且安全的方法来管理用户;密码.ADSelfService P ...

  7. CAS解决单点登录SSO

    关于CAS很多的原理和基础的配置启动,网上是很多的,我更多是结合我的实践和心得.需要了解CAS的原理,认证协议,认证流程,可以参考以下文章. 让CAS支持客户端自定义登陆页面--客户端篇 CAS原理与 ...

  8. 多域单点登录SSO系统的实现

    多域单点登录SSO系统的实现 天幻网新的规划中,将涉及到多域,如FFSKY.COM,FFSKY.CN等等,因此网上某些对同一域靠设置COOKIE的DOMAIN=".FFSKY.COM&quo ...

  9. php同子域单点登录,SSO 单点登录总结(PHP)(示例代码)

    本篇文章根据个人理解的知识整理汇总,如有不足之处,请大家多多指正. 单点登录(SSO--Single Sign On)的应用是很普遍的,尤其在大型网站系统中,比如百度,登录百度账号和,再转到百度经验. ...

  10. OAuth2实现单点登录SSO

    本文转载自:https://www.cnblogs.com/cjsblog/p/10548022.html OAuth2实现单点登录SSO 1.  前言 技术这东西吧,看别人写的好像很简单似的,到自己 ...

最新文章

  1. 双线路切换-冗余备份实验
  2. re模块(* * * * *)正则表达式
  3. HttpServlet概述及应用
  4. .NET IdentityServer4实战-开篇介绍与规划
  5. 清华大学朱旭峰:中国智库大数据报告2017预发布
  6. 有用户反映小米手机充电变慢,官方回应:天气过热
  7. zabbix企业应用之centos7安装硬件监控
  8. 常见数据库url和driver
  9. laravel php 语法,Laravel之Resource Route的点语法小技巧_PHP开发框架教程
  10. CCNA认证考试介绍
  11. Hyper-V虚拟机和虚拟化服务器区别
  12. iis7.5 php isapi映射,IIS7、iis7.5让ISAPI扩展DLL执行的方法
  13. Linux efi分区被删除了,恢复删掉的 MSR 和 EFI 分区
  14. Git GUI中文乱码问题解决方法
  15. Android中使用SVG矢量图打造多边形图形框架
  16. 2009年中国各省人均GDP排名(鄂尔多斯人均GDP将很有可能超过两万美元,全国第一)...
  17. 设计模式之简单化_Mediator中介者模式_只有一个仲裁者
  18. Window系统安装FFmpeg
  19. 用java计算电阻,NTC热敏电阻计算公式
  20. 目录 | Flink源码走读

热门文章

  1. 算子法二阶线性非齐次微分方程的通解
  2. 杰理ac18芯片_杰理AC1074 MP3解码芯片ic方案说明
  3. php网站后台开发教程,WordPress做网站后台开发教程
  4. c++2048小游戏编写
  5. 搜索引擎检索的一点经验
  6. 自定义高性能播放器, 实现边下边播缓存等功能
  7. MySQL-老杜学习笔记
  8. Arduino Mega2560 作为烧录器烧写Mega2560的bootloader
  9. 查询oracle数据库表名和中文名
  10. Neo4j 图数据库高级应用系列 / 服务器扩展指南 APOC 8.6 - 图生成 小世界模型