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

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来获取请求路径(其实一开始就该想到这里)

最新文章

  1. H5坦克大战之【玩家控制坦克移动】
  2. iptables日志探秘
  3. SparkSql 不支持Date Format (支持Timestamp)
  4. (8) 深入理解Java Class文件格式(七)
  5. MVC HTML辅助类常用方法记录
  6. Python3基础 print 输出hello world
  7. POJ 2182【树状数组】
  8. LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面
  9. mysqldump的流程
  10. 浅谈String类型
  11. xcode7 app loader error itms 90168
  12. httpd.conf配置解析php
  13. Servlet小总结(转)
  14. godot新手中文系列教程1-打包安卓
  15. 第五章:大数据 の HBase 进阶
  16. Android监听自身卸载,弹出用户反馈调查
  17. react基础&JSX基础
  18. CentOS6.5把MySQL从5.1升级到5.6后,MySQL不能启动
  19. 2017/2/16:自己ajax+json习惯性写法 代码拼接的写法 +json用post提交乱码的原因
  20. 【.Net姿势随记】const 与 readonly 初始化姿势

热门文章

  1. Spring集成RabbitMQ-连接和消息模板
  2. Android 日夜间切换Demo
  3. 201521123099 《Java程序设计》第八周学习总结
  4. 201521123103 《Java学习笔记》 第七周学习总结
  5. 201521123056 《Java程序设计》第1周学习总结
  6. 我的Emacs配置文件
  7. 201521123009 《Java程序设计》第9周学习总结
  8. 分页复用代码【Page类、JSP显示页面】
  9. Intellij idea 断点调试
  10. JavaScript基礎知識