问题解决记录:Django-restful-framework 利用Session 权限验证

346 阅读1分钟

问题描述

最近在工作中遇到这样一个需求,需要对每次后端的请求拦截进行权限验证,若每一次都是对token认证的话,请求认证服务器的次数太多,请求等待的时间也太长,同时也增加了认证服务器的负载。

想法

Django开启了Session的middleware之后,request中会附带一个sessionStorage,其是一个类字典的对象,可以在第一次token认证通过后,把信息附带到该对象中,之后请求只要检查该对象来进行认证。

其本质是利用HTTP服务端的session功能来进行缓存。

具体实现(仅供参考,实际根据业务逻辑变更)

在drf的settings中

REST_FRAMEWORK = {
    ...,
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'yourPackage.SessionAuthentication',
        'yourPackage.TokenCheck',
    ),
}

加入自定义的权限验证类,这里session验证一定要放在Token验证之前,这样只有在session验证不通过时才会走Token验证

自定义SessionAuthentication类

class SessionAuthentication(authentication.BaseAuthentication):

    def authenticate(self, request):
        # if the user has logined and not expired, request must have the 'id' in the session
        try:
            #id just for example
            id = request.session['id']
        except KeyError:
            # can't find user, not passed, need to check token
            return None
        user = User.objects.get(id=id)
        permissions = get_permissions() # 自定义获取权限函数
        return (user, permissions)

自定义TokenCheck

class TokenCheck(authentication.BaseAuthentication):

    def authenticate(self, request):
        # decode token
        token = get_token(request)
        decoded_token = decode_token(token)

        id = decoded_token.get('id')

        ...
        permissions = get_permissions(id)

        request.session['id'] = id
        request.session['token'] = token
        request.session.set_expiry(SESSION_EXIRY_TIME)
        return (user, permissions)