首先介绍装饰器,以下是一段标注了特殊输出的代码。用于帮助理解装饰器的调用过程。

import time  

def Decorator_one(arg1):
info = "\033[1;31;40mthis is Decorator_one with para " + str(arg1)
print(info)
def _Decorator_one(func):
print('\033[1;31;40mthis is _Decorator_one')
def __Decorator_one(*args, **kwargs):
def __exit__():
print('exit###############')
print('\033[1;31;40mthis is __Decorator_one')
start = time.time()
return_value = func(*args, **kwargs)
end = time.time()
result = "\033[1;31;40mDecorator: " + str((end-start) * 1000)
print(result)
print('\033[1;31;40m__Decorator_one will end')
return 'deco1'
print('\033[1;31;40m_Decorator_one will end')
return __Decorator_one
print('\033[1;31;40mDecorator_one will end')
return _Decorator_one def Decorator_two(arg2):
info = "\033[1;32;40mthis is Decorator_two with para " + str(arg2)
print(info)
def _Decorator_two(func):
print('\033[1;32;40mthis is _Decorator_two')
def __Decorator_two(*args, **kwargs):
print('\033[1;32;40mthis is __Decorator_two')
start = time.time()
return_value = func(*args, **kwargs)
end = time.time()
result = "\033[1;32;40mDecorator: " + str((end-start) * 1000)
print(result)
print('\033[1;32;40m__Decorator_two will end')
return 'deco2'
print('\033[1;32;40m_Decorator_two will end')
return __Decorator_two
print('\033[1;32;40mDecorator_two will end')
return _Decorator_two @Decorator_one(True)
@Decorator_two(False)
def testfunc(para):
print "\033[1;37;40mstart"
time.sleep(0.1)
print "\033[1;37;40mend"
return '123' if __name__ == '__main__':
aaa = testfunc(123)
print(aaa)

程序输出如下图

简单介绍一下上面的运行情况:

首先,声明装饰器的结构分为两层。如果装饰器需要包含参数,为了处理参数则分为三层。上述代码的例子则使用了三层。

最外层参数即是装饰器参数;中间层参数为被修饰的方法的方法名;最内层为被修饰的方法的参数。可在各层处理参数。

装饰器的调用顺序第一次见到的时候觉得很诡异。可以理解为两个装饰器的三层结构是并行走下去的。具体顺序见图,就不细说了。

最后,被装饰器修饰过的函数,调用之后的返回值是最后一个调用的装饰器,最内层定义函数的返回值。所以请一定记得,对被修饰函数返回值的处理,要在装饰器中完成。

以下是flask通过装饰器实现单点登录验证的方法:

单点登录的简单概念

多个网站通过同一套用户权限进行登录验证的手段。网站可以在同一个子域或跨域。这里的方法不涉及跨域。

登录及验证方法为,提供登录验证的网站在登录成功后,生成一个token添加到cookie中,用于验证用户权限。

同二级域名下的网站,或者跨域的网站,可以通过访问登录验证的网站这个子域,获取cookie中的token字段,向登录验证的网站验证权限。

代码最初是公司前辈实现的,这里呢主要是觉得如果使用调用函数的方式,在方法中验证登录非常麻烦,按照装饰器的风格改造了一下。

登录校验装饰器的实现(伪代码)(2017-06-07修改,见注释)

import request
from flask import session, request, redirect def do_ssoh(route=""):# 删去route=""
def _do_sso(func):
def __do_sso(*args, **kwargs):
# 通过request模块的cookies方法获取cookie中的信息
如果request.cookies方法有token这个key
token = request.cookies['token'].encode('utf-8')
否则跳转到sso登录页面:
return redirect(sso_url + "http://" + domain + route)#route 替换为 request.path # 通过request模块的header方法或remote_addr方法,获取用户真实ip
client_ip = request.headers.get('X-Forwarded-For', '')
if not client_ip:
client_ip = request.remote_addr # 去sso站点检查token是否有效
try:
result = do_post(sso_url, '...token...')
检查访问失败则跳转到sso登录页面:
return redirect(sso_url + "http://" + domain + route)#route 替换为 request.path 如果检查通过,则在session中保存用户名:
session['username'] = result['result']['name']
return func()
否则跳转到登录页面:
return redirect(sso_url + "http://" + domain + route)#route 替换为 request.path return __do_ssoauth
return _do_sso

装饰器的使用(2017-06-07修改,见注释)

@app.route('/index')
@account.do_ssoauth('/index') #删去参数
def index():
response = make_response(render_template(
"/index.html",
username=session['username']))
return response

这样,访问xxx/index的时候就会去sso站点验证是否登录。

关于跨域的实现暂时没有需求,也就没有去做。个人以为,需要前端配合,添加跨域访问的js代码,去获取sso所在子域下的cookie,再去sso站点验证。不确保思路正确哦~。

2017-06-07修改原因:在项目中使用了flask 蓝图的动态url前缀之后,其实参数是不太能良好的配置为访问的url。尤其是在g需要一个运行时的上下文环境的时候(就是在运行时才有这个量),而程序已开始跑,就会把这个装饰器注册(or what?),这时候g变量其实不存在。现修改为不需要参数,在装饰器中使用request.path来获取请求路径(其实一开始就该想到这里)

python装饰器 & flask 通过装饰器 实现 单点登录验证的更多相关文章

  1. 重学 Java 设计模式:实战装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 对于代码你有编程感觉吗 很多人写代码往往是没有编程感觉的,也就是除了可以把功能按照固 ...

  2. python 学习笔记7(装饰器)

    闭包(closure)是函数式编程的重要的语法结构. 定义:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure). def outer ...

  3. Python成长之路_装饰器

    一.初入装饰器 1.首先呢我们有这么一段代码,这段代码假设是N个业务部门的函数 def f1(aaa): print('我是F1业务') if aaa == 'f1': return 'ok' def ...

  4. 简学Python第四章__装饰器、迭代器、列表生成式

    Python第四章__装饰器.迭代器 欢迎加入Linux_Python学习群  群号:478616847 目录: 列表生成式 生成器 迭代器 单层装饰器(无参) 多层装饰器(有参) 冒泡算法 代码开发 ...

  5. 轻松理解python中的闭包和装饰器 (下)

    在 上篇 我们讲了python将函数做为返回值和闭包的概念,下面我们继续讲解函数做参数和装饰器,这个功能相当方便实用,可以极大地简化代码,就让我们go on吧! 能接受函数做参数的函数我们称之为高阶函 ...

  6. 初学 Python(十五)——装饰器

    初学 Python(十五)--装饰器 初学 Python,主要整理一些学习到的知识点,这次是生成器. #-*- coding:utf-8 -*- import functools def curren ...

  7. Python入门之函数的装饰器

    本章目录: 装饰器: 一.为什么要用装饰器 二.什么是装饰器 三.无参装饰器 四.装饰器语法糖 五.认证装饰器实现 六.叠加多个装饰器 七.带参装饰器 ======================== ...

  8. Python全栈开发之---装饰器

    1.装饰器的形成过程 import time def func1(): print('in func1') def timer(func): def inner(): start = time.tim ...

  9. python中的闭包和装饰器

    重新学习完了函数,是时候将其中的一些重点重新捋一捋了,本次总结的东西只有闭包和装饰器 1.闭包 闭包是python函数中的一个比较重要功能,一般闭包都是用在装饰器上,一般学完闭包就会去学习装饰器,这俩 ...

随机推荐

  1. Linaro系统获取root权限方法

    在Zedboard上根据教程安装Linaro Ubuntu后出现一只无法获取Root权限,导致无法挂载U盘等问题. 具体体现在sudo -s命令之后,出现如sudo:must be setuid ro ...

  2. 【★】KMP算法完整教程

    KMP算法完整教程 全称:                               Knuth_Morris_Pratt Algorithm(KMP算法) 类型:                 ...

  3. ps中如何让图层在画布内水平居中

    下图每个小logo图案距离它们的上参考线的距离均为10px,而我们如何让图层在画布内水平居中??? 如上图中三个图层的图案是用来给Html/Css中的background属性使用的,虽然可以通过鼠标拖 ...

  4. Linux cat /proc/meminfo 输出分析

    $cat /proc/meminfoMemTotal:        2052440 kB //总内存MemFree:           50004 kB //空闲内存Buffers:        ...

  5. 【集美大学1411_助教博客】团队作业3——需求改进&系统设计 成绩

    看到同学们越来越认真了,助教非常高兴.大家已经开始了alpha冲刺,请控制好进度.成功的关键就是不断迭代,不断迭代. 关于leangoo 我看到所有组的同学都已经开始使用leangoo,请大家把助教加 ...

  6. 集美大学网络1413第十五次作业成绩(团队十) -- 项目复审与事后分析(Beta版本)

    题目 团队作业10--项目复审与事后分析(Beta版本) 团队作业10成绩 --团队作业10-1 Beta事后诸葛亮  团队/分值 设想和目标 计划 资源 变更管理 设计/实现 测试/发布 团队的角色 ...

  7. 结对作业1----基于flask框架的四则运算生成器

    011.012结对作业 coding地址:https://coding.net/u/nikochan/p/2nd_SE/git 一.作业描述 由于上次作业我没有按时完成,而且庞伊凡同学编程能力超棒,所 ...

  8. 英语词典Alpha版本发布说明

    Alpha版本发布说明 功能: ·简洁的应用界面,不被无良的广告弹窗影响  ·功能直接,在需要查词时及时出现,没有每日一句精选文章等杀了你的流量,在学习过程中更加专注! ·采用金山词霸API,提供发音 ...

  9. 团队作业4——第一次项目冲刺(ALpha版本)第三天

    一.Daily Scrum Meeting照片 二.燃尽图 三.项目进展 1.界面 完成了前端的HTML页面设计 2.功能 完成了后端数据处理的全部基本功能: 数据结构设计及数据交互操作 博客页面数据 ...

  10. vbs读取excel的一个实例

    功能:在excel中对ip与loginType这两列进行遍历读取.本程序依赖于excel文件的"sheet2"表单中具有这两列. dim dictTarget, objExcel ...