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 文件添加中间件
学习最大的乐趣在于分享,我是绝世老中医,欢迎来诊
个人qq:1978529954