python装饰器 & flask 通过装饰器 实现 单点登录验证

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

 

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

 

转载于:https://www.cnblogs.com/blaketairan/p/7136732.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单点登录(SSO)是一种身份认证技术,允许用户在多个应用程序或系统中使用同一组凭据进行登录。Python实现SSO单点登录可以使用多种方式,其中一种常用的方式是使用JSON Web Token(JWT)。 以下是一个简单的Python实现SSO单点登录的步骤: 1. 安装所需库 使用pip安装flask和pyjwt库,这两个库分别用于实现Web应用程序框架和JWT令牌生成和验证。 ``` pip install flask pyjwt ``` 2. 创建身份认证服务器 创建一个Flask应用程序作为身份认证服务器。该应用程序将处理用户登录和JWT令牌的生成。 ```python from flask import Flask, request, jsonify import jwt app = Flask(__name__) @app.route('/login', methods=['POST']) def login(): # 在此处验证用户名和密码 # 如果验证通过,则生成JWT令牌并返回给客户端 payload = {'username': 'user123'} token = jwt.encode(payload, 'secret', algorithm='HS256') return jsonify({'token': token.decode('UTF-8')}) if __name__ == '__main__': app.run() ``` 在上面的代码中,'login'路由用于处理用户登录请求。如果用户名和密码验证通过,则生成JWT令牌并返回给客户端。 3. 集成SSO到应用程序 在需要实现SSO的应用程序中,需要验证用户的JWT令牌并授予访问权限。 ```python from flask import Flask, request, jsonify import jwt app = Flask(__name__) @app.route('/protected', methods=['GET']) def protected(): # 验证JWT令牌 token = request.headers.get('Authorization') try: payload = jwt.decode(token, 'secret', algorithms=['HS256']) return jsonify({'message': 'Access granted for user ' + payload['username']}) except jwt.ExpiredSignatureError: return jsonify({'message': 'Token has expired'}) except jwt.InvalidTokenError: return jsonify({'message': 'Invalid token'}) if __name__ == '__main__': app.run() ``` 在上面的代码中,'protected'路由用于保护需要授权用户才能访问的资源。它从请求头中获取JWT令牌并验证它。如果令牌有效,则授权用户访问资源。 4. 集成登录页面 在需要实现SSO的应用程序中,需要提供一个登录页面,使用户能够登录并获得JWT令牌。 ```html <!DOCTYPE html> <html> <head> <title>Login Page</title> </head> <body> <h1>Login Page</h1> <form action="/login" method="POST"> <label for="username">Username:</label> <input type="text" id="username" name="username"><br><br> <label for="password">Password:</label> <input type="password" id="password" name="password"><br><br> <input type="submit" value="Login"> </form> </body> </html> ``` 在上面的代码中,登录表单将向'login'路由提交用户名和密码。如果验证通过,则将JWT令牌返回给客户端,否则显示错误消息。 以上是一个简单的Python实现SSO单点登录的步骤。需要注意的是,这只是一个基本实现,还需要考虑安全性和其他方面的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值