前言

参考本系列之前的文章,我们已经搭建了ldap并且可以通过django来操作ldap了,剩下的就是下游系统的接入了,现在的应用场景,我是分了2个层次,第一层次是统一认证,保证各个系统通过ldap来维护统一的用户名和密码,第二层次就是sso单点登录,即一个系统登录,其他系统即是登录状态,一个系统登出,其他系统也自动登出,也就是我们登录公司内部的N个系统,其实总共只需要登录一次即可。

目前,django的下游系统可以接入单点,理论上,只要语言支持memcache客户端,通过session维持登录状态,都可以接入,但类似jira这种商用产品,由于没有二次开发的能力,所以只能支持到统一密码的层面了。

代码实现

首先在下游系统的settings.py需要进行一定的配置,其中,session要走我们的共享mc中,这样才能获取到sso系统传入的session,以达到单点登录的目的。

LOGIN_URL = "http://sa.ssotest.net/account/login/"  # 跳转到sso系统的登录上
PERM_DENY_URL = "http://sa.ssotest.net/403.html" # 这个是自己加的一个配置,如果下游系统没有sso用户的权限,会跳转到deny页面上
#LOGIN_URL = "/account/login/" # 之前走本地的配置 # ### session config BEGIN ### #
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_COOKIE_AGE = 86400 # 设置session有效期为一天,默认两周
SESSION_COOKIE_DOMAIN = ".ssotest.net"
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'ldap1.prod.bj1.ssotest.net:11211',
'ldap2.prod.bj1.ssotest.net:11211',
],
'TIMEOUT': 60 * 15, # 缓存默认过期时间
'OPTIONS': {
'MAX_ENTRIES': 3000 # 最大缓存个数
}
}
}
# ### session config END ### #

设定一个下游系统专用的验证登录状态和登出的装饰器,放在backend/decorators/login_auth.py以代替你可能在用的django自带的login_required

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from SQLaudit import settings_prod as settings
from django.shortcuts import redirect
from web_sql import models
import json
from django.db import transaction
from django.core.cache import cache
from django.contrib import auth # ########## 用于验证用户是否登陆的装饰器 ##########
def login_sso(func):
""" 如果用户已经登陆,则执行相应的Views中的函数,否则,跳转至 settings中设置的LOGIN_URL地址,即: '/account/login/'"""
def wrapper(request, *args, **kwargs):
sso_dic = request.session.get('sso_dic', None) # 这个字典在sso系统中登录成功后,由sso设定在request.session中
if not sso_dic:
login_url = '%s?back=%s' % (settings.LOGIN_URL, request.get_raw_uri()) # 把当前站点的url传参给back,如果在sso中登录成功会自动redirect到back
return redirect(login_url)
try:
sso_dic = json.loads(sso_dic)
# 用户对象优先从cache缓存中取出,如没有,从数据库中取出,key: sso_uid_sqladmin.ssotest.net:8009_qudong
cache_user = cache.get('sso_uid_%s_%s' % (request.get_host(), sso_dic.get('sso_username')))
user_obj = cache_user if cache_user else \
models.User.objects.filter(username=sso_dic.get('sso_username'),
userprofile__name=sso_dic.get('sso_chinese_name'),
email=sso_dic.get('sso_email')).first()
if not user_obj: # 如果上下游用户信息不一致,创建或更新下游信息
with transaction.atomic():
''' 以下部分需要根据各下游系统,注册用户方法不同,而进行修改 '''
user_obj, status = models.User.objects.update_or_create(username=sso_dic.get('sso_username'),
defaults={'email': sso_dic.get('sso_email')})
group_obj = models.Group.objects.get(name='开发人员') # 新增用户默认属于开发人员组
user_obj.groups.add(group_obj)
models.UserProfile.objects.update_or_create(user=user_obj,
defaults={'name': sso_dic.get('sso_chinese_name')})
if not user_obj.is_active: # 用户在下游系统被禁用
raise Exception(u'用户被禁用')
except Exception:
login_url = '%s?back=%s' % (settings.PERM_DENY_URL, request.get_raw_uri())
return redirect(login_url) # 下游系统在同步信息中出现问题,跳转到deny页面
else:
# 如用户已同步,添加缓存,使用cache.add方法,如已有cache,不进行处理;cache.set方法会重新覆盖cache.缓存失效时间5分钟,期间,登录用户状态不会被修改
cache.add('sso_uid_%s_%s' % (request.get_host(), sso_dic.get('sso_username')), user_obj, 60 * 5)
request.user = user_obj
return func(request, *args, **kwargs)
return wrapper # ########## 用于用户登出的装饰器,主要用于session清除后,缓存的清除 ##########
def logout_sso(func):
def wrapper(request):
try:
sso_dic = request.session.get('sso_dic', None)
auth.logout(request)
sso_dic = json.loads(sso_dic)
cache.delete('sso_uid_%s_%s' % (request.get_host(), sso_dic.get('sso_username'))) # 除了auth.logout额外添加取出之前添加的cache动作
except Exception:
pass
return func(request)
return wrapper

顺道提一下django的cache,我们的session和cache都走的settings.py的CACHES属性,我们这里是缓存到memcache中,django cache部分的官网中文说明:http://python.usyiyi.cn/translate/django_182/topics/cache.html

django可以实现站点级的缓存,某个url的缓存,某个view的缓存,某个模板片段的缓存,某个数据的缓存(底层cache api),具体可以参考上边的文档,写的很细致了,测试了一下,比如进行了view的缓存,它是把整个html包括静态和动态的都缓存住,这样如果我们的数据更新了,那就只能等到缓存过期了。我这里由于只是为了缓存一个数据对象(user_obj),所以只用了cache api,具体就是add,get,delete方法,注意add和set的区别,add如果已有cache将不处理,set是不管有没有,都重新设置

如果要缓存某个view也很方便,直接在view上添加装饰器cache_page(60 * 15) ,缓存15分钟

调用的时候,将原来的验证登录的装饰器替换成login_sso

@logout_sso
def sql_logout(request):
return redirect(settings.LOGIN_URL) @login_sso
def sql_base(request):
user = request.user # request.user通过login_sso已经定义,可以直接把当前登录的user对象拿来用了
return render(request, 'audit/sql_base.html', {})

结语

经过以上一系列的博客,大体上熟悉了整个sso+统一认证的流程,期间还是有一些不太理想的地方,比如非django系统如何更好的支持sso,因为我的方案里,sso的核心是共享session,而session存在django的request中,不知道其他语言的系统如何获取这个request.session,另外整个单点系统只支持到同域的跨站级别,还没考虑跨域的问题,欢迎牛人指导。

参考资料

http://python.usyiyi.cn/translate/django_182/topics/cache.html

[原创]django+ldap实现单点登录(装饰器和缓存)的更多相关文章

  1. [原创]django+ldap+memcache实现单点登录+统一认证

    前言 由于公司内部的系统越来越多,为了方便用户使用,通过django进行了单点登录和统一认证的尝试,目前实现了django项目的单点登录和非django项目的统一认证,中间波折挺多,涉及的技术包括dj ...

  2. [原创]django+ldap实现统一认证部分二(python-ldap实践)

    前言 接上篇文章 [原创]django+ldap实现统一认证部分一(django-auth-ldap实践) 继续实现我们的统一认证 python-ldap 我在sso项目的backend/lib/co ...

  3. Django(十六)基于模板的登录案例:登录装饰器、csrf攻击方式及防护、ajax的Post 的csrf开启写法、生成验证码、加验证码登录、反向解析+传参

    一.csrf攻击 1.1 csrf攻击(跨站请求伪造) [csrf攻击即]:通过第3方网站,伪造请求(前提条件是你已经登录正常网站,并保存了session或cookie登录信息且没有退出),第三方网站 ...

  4. [原创]django+ldap实现统一认证部分一(django-auth-ldap实践)

    前言 接之前我的文章,django+ldap+memcache实现单点登录+统一认证 ,ldap部署相关,ldap双机\LAM配置管理\ldap备份还原,目前来说,我们已经有了高可用性的ldap环境了 ...

  5. python框架之Django(8)-CBV中添加装饰器

    现有如下检查登录装饰器: from functools import wraps def check_login(func): @wraps(func) def inner(request, *arg ...

  6. Django基础七之CBV装饰器和中间件

    Django基础七之CBV装饰器和中间件 目录 Django基础七之CBV装饰器和中间件 1. CBV加装饰器 2. Django中间件 2.1 Django中间件介绍 2.2 自定义中间件 2.2. ...

  7. python 之 Django框架(Django框架简介、视图装饰器、request对象、Response对象)

    12.33 Django框架简介: MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器( ...

  8. Django学习手册 - 登录装饰器

    # 装饰器定义 def auth(func): def inner(request,*args,**kwargs): v = request.COOKIES.get("user") ...

  9. Python - Django - 在 CBV 中使用装饰器

    urls.py: from django.conf.urls import url from app02 import views urlpatterns = [ # app02 url(r'^app ...

随机推荐

  1. Hyper-V2:向VM增加虚拟硬盘

    使用Hyper-V创建VM,在VM成功安装OS之后,发现VM只有一个逻辑盘C,用于存储VM的操作系统.在产品环境中,需要向VM增加虚拟硬盘,便于将数据单独存储在不同的逻辑盘符中.在Hyper-V中,分 ...

  2. .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”

    FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...

  3. [C#] 剖析 AssemblyInfo.cs - 了解常用的特性 Attribute

    剖析 AssemblyInfo.cs - 了解常用的特性 Attribute [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5944391.html 序 ...

  4. 【NLP】揭秘马尔可夫模型神秘面纱系列文章(一)

    初识马尔可夫和马尔可夫链 作者:白宁超 2016年7月10日20:34:20 摘要:最早接触马尔可夫模型的定义源于吴军先生<数学之美>一书,起初觉得深奥难懂且无什么用场.直到学习自然语言处 ...

  5. [转载]Cookie/Session的机制与安全

    Cookie和Session是为了在无状态的HTTP协议之上维护会话状态,使得服务器可以知道当前是和哪个客户在打交道.本文来详细讨论Cookie和Session的实现机制,以及其中涉及的安全问题. 因 ...

  6. SQL Server2008R2 在windows8上安装,出现“兼容性”和 “执行未经授权的操作”的错误!

    本人是windows8.1的操作系统,亲测安装成功 解决方法如下: 1.卸载干净sql Server2008r2,包括注册表内容,删除c盘下的安装路径! 2.关闭防火墙(这步很重要) 3.断开网络连接 ...

  7. 打破陈规抓痛点,H3 BPM10.0挑战不可能

    高效益意味着相似的运营活动比竞争对手做得更好,而战略定位则意味着企业在运营活动中有区别于竞争对手的实施方式,即差异化竞争.在新经济体下,面对社会的变革.市场的竞争环境.不断攀升的成本压力,几乎没有企业 ...

  8. Android之SAX解析XML

    一.SAX解析方法介绍 SAX(Simple API for XML)是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备. SAX解析器是一种基于事件的解析器,事件驱动 ...

  9. kvm 使用入门详解

    kvm 是虚拟化技术的一个典型实现,功能非常强大,使用很方便.kvm 本身主要实现对 CPU 的虚拟化,内存和IO的虚拟化使用了开源软件 qemu,qemu 是纯软件层面的虚拟化,其实就是个模拟器.k ...

  10. 让 ASP.NET vNext 在 Mac OS 中飞呀飞。。。

    写在前面 阅读目录: 娓娓道来 Install ASP.NET vNext Command Line Tools 安装 Homebrew 使用 Homebrew,安装 KVM Install Subl ...