Django jwt token验证

Django 自带的登录验证是使用session 验证的,适用于web;今天来个通过token验证的,适用于web + app

import jwt
import datetime
from jwt import exceptions
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
import logging

log = logging.getLogger("log")

JWT_SALT = "ds()udsjo@jlsdosjf)wjd_#(#)$"


def create_token(payload, timeout=600):
    # 声明类型,声明加密算法
    headers = {
        "type": "jwt",
        "alg": "HS256"
    }
    # 设置过期时间
    payload['exp'] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)
    result = jwt.encode(payload=payload, key=JWT_SALT, algorithm="HS256", headers=headers).decode("utf-8")
    # 返回加密结果 注意添加jwt前缀,解密会用到
    return "jwt " + result


def parse_payload(token):
    """
    用于解密
    :param token:
    :return:
    """
    result = {"status": False, "data": None, "error": None}
    try:
        # 进行解密
        verified_payload = jwt.decode(token, JWT_SALT, True)
        result["status"] = True
        result['data'] = verified_payload
    except jwt.ExpiredSignatureError:
        result['error'] = 'token已失效'
        log.error("ExpiredSignatureError")
    except jwt.DecodeError:
        result['error'] = 'token认证失败'
    except jwt.InvalidTokenError:
        result['error'] = '非法的token'
    return result


class JwtQueryParamAuthentication(BaseAuthentication):
    """
    用户需要在url中通过参数进行传输token,例如:
    http://www.pythonav.com?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzM1NTU1NzksInVzZXJuYW1lIjoid3VwZWlxaSIsInVzZXJfaWQiOjF9.xj-7qSts6Yg5Ui55-aUOHJS4KSaeLq5weXMui2IIEJU
    """

    def authenticate(self, request):
        # 从url上获取jwt token
        log.info("进入token校验")
        try:
            token = request.META.get("HTTP_TOKEN")
        except Exception as e:
            log.error("获取token失败, %s" % e)
            print("token 异常了")
            raise
        payload = parse_payload(token)
        if not payload['status']:
            raise exceptions.AuthenticationFailed(payload)
        log.info("校验完成")
        # 如果想要request.user等于用户对象,此处可以根据payload去数据库中获取用户对象。
        return (payload, token)


class JwtAuthorizationAuthentication(BaseAuthentication):
    """
    用户需要通过请求头的方式来进行传输token,例如:
    Authorization:jwt eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzM1NTU1NzksInVzZXJuYW1lIjoid3VwZWlxaSIsInVzZXJfaWQiOjF9.xj-7qSts6Yg5Ui55-aUOHJS4KSaeLq5weXMui2IIEJU
    """

    def authenticate(self, request):
        # 非登录页面需要校验token,从头信息拿去JWT Token
        authorization = request.META.get('HTTP_AUTHORIZATION', '')
        auth = authorization.split()
        if not auth:
            raise exceptions.AuthenticationFailed({'error': '未获取到Authorization请求头', 'status': False})
        if auth[0].lower() != 'jwt':
            raise exceptions.AuthenticationFailed({'error': 'Authorization请求头中认证方式错误', 'status': False})

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

        token = auth[1]
        result = parse_payload(token)
        if not result['status']:
            raise exceptions.AuthenticationFailed(result)

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

上面的代码块分别定义了加密解密方法

from django.utils.deprecation import MiddlewareMixin
from common.jwt_auth import JwtAuthorizationAuthentication
from django.http.response import JsonResponse
from common.enums import StatusCodeEnum
import logging

log = logging.getLogger("log")

class AuthMiddlewareMixin(MiddlewareMixin):
   "定义中间件"
    def process_view(self, request, view_func, view_args, view_kwargs):
        # process_view 的参数是固定的,不能少一个
        # 排除登录和注册接口
        skip_urls = ["/user/login", "/user/registration"]
        if request.path in skip_urls:
            print("跳过")
            log.info("跳过")
            return
        # 如果非登录接口,校验token,不通过返回特殊code
        try:
            JwtAuthorizationAuthentication().authenticate(request)
        except Exception as e:
            log.error(str(e))
            # 返回格式自行定义
            return JsonResponse({"code": StatusCodeEnum.TOKEN_ERR_CODE.code, "msg": StatusCodeEnum.TOKEN_ERR_CODE.msg})
    

最后别忘记在setting 文件添加中间件

 

posted @ 2022-11-16 16:00  绝世老中医  阅读(811)  评论(0编辑  收藏  举报