zoukankan      html  css  js  c++  java
  • Flask-Login中装饰器@login_manager.user_loader的作用及原理

    Flask-Login通过装饰器@login_required来检查访问视图函数的用户是否已登录,没有登录时会跳转到login_manager.login_view = 'auth.login'所注册的登录页。登录时即需调用login_user()函数,而在内部调用了由我们注册的回调函数。

    Flask-Login就是通过装饰器,来注册回调函数,当没有sessionID时,通过装饰器指定的函数来读取用户到session中,达到在前端模板中调用当前登录用户current_user的目的,该装饰器就是:

    @login_manager.user_loader

    其功能类似如下

    class Test():  
        # 在Test中并没有真正的定义callback
        def feature(self):  
            self.callback()  
          
        def decorate(self, func):  
            self.callback=func  
            return func  
    
    test =  Test()  
    
    # 将fun注册为回调函数
    @test.decorate  
    def fun():  
        print(1)  
      
    # 调用feature将触发回调函数      
    test.feature()  # 1

    装饰器user_loader:

    def user_loader(self, callback):
            '''
            This sets the callback for reloading a user from the session. The
            function you set should take a user ID (a ``unicode``) and return a
            user object, or ``None`` if the user does not exist.
    
            :param callback: The callback for retrieving a user object.
            :type callback: callable
            '''
            self.user_callback = callback
            return callback

    这个装饰器的目的即将回调函数赋给self.user_callback

    在login_user函数内部:

    user_id = getattr(user, current_app.login_manager.id_attribute)()
    session['user_id'] = user_id # 在这里设置用户id
    session['_fresh'] = fresh
    session['_id'] = current_app.login_manager._session_identifier_generator()

    if remember:
    session['remember'] = 'set'
    if duration is not None:
    try:
    # equal to timedelta.total_seconds() but works with Python 2.6
    session['remember_seconds'] = (duration.microseconds +
    (duration.seconds +
    duration.days * 24 * 3600) *
    10**6) / 10.0**6
    except AttributeError:
    raise Exception('duration must be a datetime.timedelta, '
    'instead got: {0}'.format(duration))

    _request_ctx_stack.top.user = user
    user_logged_in.send(current_app._get_current_object(), user=_get_user())

    调用时将user的属性写入session,并绑定到当前的请求上下文。由于HTTP是无状态的,每次发起新请求时flask会创建一个请求上下文,在分发路由时flask-login根据cookie判断用户并绑定到当前的请求上下文,由于这种绑定关系的存在,那么每次新的请求发生时都需要获取user看一下最后绑定的代码:

    def reload_user(self, user=None):
            ctx = _request_ctx_stack.top
    
            if user is None:
                user_id = session.get('user_id')
                if user_id is None:
                    ctx.user = self.anonymous_user()
                else:
                    if self.user_callback is None:
                        raise Exception(
                            "No user_loader has been installed for this "
                            "LoginManager. Add one with the "
                            "'LoginManager.user_loader' decorator.")
                    user = self.user_callback(user_id)
                    if user is None:
                        ctx.user = self.anonymous_user()
                    else:
                        ctx.user = user
            else:
                ctx.user = user
    这个函数即未获得user时调用的,这时就必须调用回调函数self.user_callback
     
    自己定义的回调函数:
    @login_manager.user_loader
    def load_user(user_id):
            return User.query.get(int(user_id))

    self.user_callback就是装饰器装饰的回调函数load_user(),reload_user的作用就是当user无值时调用该方法获取user并绑定到当前的请求上下文,绑定的意义在于每次当我们使用current_user的时候,会直接从当前上下文中返回。


    装饰器login_required:

    def login_required(func):
      
        @wraps(func)
        def decorated_view(*args, **kwargs):
            if current_app.login_manager._login_disabled:
                return func(*args, **kwargs)
            elif not current_user.is_authenticated:
                return current_app.login_manager.unauthorized()
            return func(*args, **kwargs)
        return decorated_view
  • 相关阅读:
    hadoop12---java并发编程的一些总结
    hadoop11----socket
    springboot-vue项目后台2---pojo对查询结果手动分组
    hadoop10---消息队列
    hadoop09----线程池
    hadoop08---读写锁
    hadoop07---synchronized,lock
    hadoop06---多线程
    Java Applet与Java Application的区别
    HTML中id、name、class 区别
  • 原文地址:https://www.cnblogs.com/eat-w/p/12057189.html
Copyright © 2011-2022 走看看