restframework jwt登录验证

前言

  • 本套代码借鉴其他博主,大家可去该博主的博客详细了解一下jwt实现流程和具体表现,本文只是做了某些代码的删减。

  • http本身是无状态的,所以无法设置jwt刷新和清除操作,违背了jwt的初衷,但业务需要实现某些功能,比如:退出登录,保持登录有效期等操作时。
    就得借助数据库进行存储,在业务逻辑上进行数据库的操作实现退出登录和刷新token。(以上个人理解,如有不同见解可以提出互相讨论。)

  • 武沛齐的博客地址:https://www.cnblogs.com/wupeiqi/p/11854573.html

代码实现

  • 首先我们在项目目录下新建utils/jwt_auth.py文件,编写两个函数"生成token"和"校验token"
import jwt
import datetime
from jwt import exceptions
from mysite.settings import SECRET_KEY      # 配置文件的加密字符串
from rest_framework import exceptions as es

def create_token(payload, timeout=20):
    """
    生成token
    :param payload:     例如:{'user_id':1,'username':'wupeiqi'}用户信息
    :param timeout:     token的过期时间,默认20分钟
    :return:
    """
    headers = {
        'typ': 'jwt',
        'alg': 'HS256'
    }

    # 对传进来的payload字典添加键值对,过期时间
    payload['exp'] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)

    # 加密
    result = jwt.encode(payload=payload, key=SECRET_KEY, algorithm="HS256", headers=headers).decode('utf-8')
    return result


def parse_payload(token):
    """
    校验token并获取payload
    :param token:
    :return:
    """

    try:
        verified_payload = jwt.decode(token, SECRET_KEY, True)
    except exceptions.ExpiredSignatureError:
        raise es.AuthenticationFailed({'detail': 'token已失效'})
    except jwt.DecodeError:
        raise es.AuthenticationFailed({'detail': 'token认证失败'})
    except jwt.InvalidTokenError:
        raise es.AuthenticationFailed({'detail': '非法的token'})

    return verified_payload

  • 新建utils/auth.py文件,在该文件中编写我们自定义的认证组件,
    必须继承restframework中的认证类BaseAuthentication
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from polls.utils.jwt_auth import parse_payload


class JwtAuthorizationAuthentication(BaseAuthentication):
    """
    用户需要通过请求头的方式来进行传输token
    """

    def authenticate(self, request):

        # 这里选择从请求头方式获取token
        authorization = request.META.get('HTTP_AUTHORIZATION', '')
        auth = authorization.split()
        if not auth:
            raise exceptions.AuthenticationFailed({'detail': '未获取到Authorization请求头'})
        if auth[0].lower() != 'jwt':
            raise exceptions.AuthenticationFailed({'detail': "Authorization请求头中认证方式错误"})

        if len(auth) == 1:
            raise exceptions.AuthenticationFailed({'detail': "非法Authorization请求头"})
        elif len(auth) > 2:
            raise exceptions.AuthenticationFailed({'detail': "非法Authorization请求头"})

        token = auth[1]
        result = parse_payload(token)

        # 如果想要request.user等于用户对象,此处可以根据payload去数据库中获取用户对象。
        return (result, token)

  • 我们需要在settings.py全局配置文件中加入我们的认证组件作为全局认证
    每条请求必须携带token并通过认证才能进入视图函数。
REST_FRAMEWORK = {
    # 全局使用认证类
    #注意里面是路径,将认证类写在utils文件夹的auth.py中,'api'填写你项目目录
    "DEFAULT_AUTHENTICATION_CLASSES":['api.utils.auth.JwtAuthorizationAuthentication', ],
}
  • 像我们的登录/注册是不需要认证的,我们可以在视图中屏蔽认证。
class LoginView(APIView):
    authentication_classes = []
    ......
原文地址:https://www.cnblogs.com/se7enjean/p/13187788.html