flask-login & 小程序登录验证

最近在做小程序的后端API工作,发现小程序是不存储cookie,仅提供LocalStorage,这样平时在APP所用的cookie验证用户身份就不能用在小程序上。看了flask-login的文档,发现除了cookie验证身份外,还提供通过请求参数和头部来验证用户身份的方法。下面通过阅读flask的源码来解读整个过程。

  • 需要登录验证的视图函数加上login_required的装饰器
@app.route('/userinfo')
@login_required
def user_info():
    pass

login_required的源码

def login_required(func):
    @wraps(func)
    def decorated_view(*args, **kwargs):
        if request.method in EXEMPT_METHODS:
            return func(*args, **kwargs)
        elif 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

第一个条件判断请求方法是否在白名单中,是的话不进行登录验证,默认请求是OPTION的话不进行验证。第二个判断login_manager是否配置为不验证登录。以上都不满足的话则判断当前用户是否是通过登录授权的。登录授权的本质问题就是能否通过请求所带的cookie或者参数等识别到用户。下来来看如何获取到current_user

  • 获取current_user

flask_login/utils.py中定义了current_user

current_user = LocalProxy(lambda: _get_user())

然后看到_get_user的定义

def _get_user():
    if has_request_context() and not hasattr(_request_ctx_stack.top, 'user'):
        current_app.login_manager._load_user()

    return getattr(_request_ctx_stack.top, 'user', None)

接着来看login_manager._load_user

def _load_user(self):
    config = current_app.config
    if config.get('SESSION_PROTECTION', self.session_protection):
        deleted = self._session_protection()
        if deleted:
            return self.reload_user()

    if is_missing_user_id:
        cookie_name = config.get('REMEMBER_COOKIE_NAME', COOKIE_NAME)
        header_name = config.get('AUTH_HEADER_NAME', AUTH_HEADER_NAME)
        has_cookie = (cookie_name in request.cookies and
                      session.get('remember') != 'clear')
        if has_cookie:
            return self._load_from_cookie(request.cookies[cookie_name])
        elif self.request_callback:
            return self._load_from_request(request)
        elif header_name in request.headers:
            return self._load_from_header(request.headers[header_name])

    return self.reload_user()

从这个方法的最后可以看到,提供了三种方法加载用户。第一种是_load_from_cookie,接着是_load_from_request,最后是_load_form_header。第一种小程序不支持,第三种不久后将要被弃用,所以这里主要是用第二种,通过request对象来加载用户。

_load_from_request的定义

def _load_from_request(self, request):
    user = None
    if self.request_callback:
        user = self.request_callback(request)
    if user is not None:
        self.reload_user(user=user)
        app = current_app._get_current_object()
        user_loaded_from_request.send(app, user=_get_user())
    else:
        self.reload_user()

如果存在request_callback,就调用该方法。看下下面这段代码

def request_loader(self, callback):
    self.request_callback = callback
    return callback

这个方法也是一个装饰器,类似于常用的login_manager.load_user装饰器,详细用法可以查看官方文档

  • 自定义授权检查方法

这是我在小程序接口中定义的授权检查方法

@login_manager.request_loader
def load_user_from_request(request):
    login_key = request.headers.get('login_key')
    if login_key:
        user_info = current_app.redis.get(login_key)
        if user_info:
            # load user
            # return user
            pass
    return None

用户通过小程序授权登录后,自定义一个login_key作为存储用户唯一识别信息的Redis键,将其返回给小程序,之后每次小程序请求都要带上这个key,这样就能完成一次登录校验。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 22年12月更新:个人网站关停,如果仍旧对旧教程有兴趣参考 Github 的markdown内容[https://...
    tangyefei阅读 35,310评论 22 257
  • 最近在学习flask,用到flask-login,发现网上只有0.1版本的中文文档,看了官方已经0.4了,并且添加...
    ZZES_ZCDC阅读 11,211评论 3 24
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,120评论 19 139
  • 第二部分 Blog例子 第八章 用户验证 大部分程序需要追踪用户身份。当用户连接到程序,通过一系列步骤使自己的身份...
    易木成华阅读 5,117评论 0 4
  • 1.补全代码 2.配置tomcat 3.设置文本背景颜色 4.自动补全代码快捷键改成Ctrl+Space 5.安装...
    GS的BLOG阅读 1,580评论 0 0

友情链接更多精彩内容