JWT
"""1、组成: header.payload.signature 头.载荷.签名2、距离:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Im93ZW4iLCJleHAiOjE1NTgzMDM1NDR9.4j5QypLwufjpqoScwUB9LYiuhYcTw1y4dPrvnv7DUyo3:介绍:header:一般存放如何处理token的方式:加密的算法、是否有签名等payload:数据的主体部分:用户信息、发行者、过期时间等signature:签名:将header、payload再结合密码盐整体处理一下"""
工作原理
"""1) jwt = base64(头部).base64(载荷).hash256(base64(头部).base(载荷).密钥)2) base64是可逆的算法、hash256是不可逆的算法3) 密钥是固定的字符串,保存在服务器"""
drf-jwt
官网
https://github.com/jpadilla/django-rest-framework-jwt
安装子:虚拟环境
pip install djangorestframework-jwt
使用:user/urls.py
from django.urls import pathfrom rest_framework_jwt.views import obtain_jwt_tokenurlpatterns = [ path('login/', obtain_jwt_token),]
测试接口:post请求
"""postman发生post请求接口:http://api.luffy.cn:8000/user/login/数据:{ "username":"admin", "password":"admin"}"""
drf-jwt开发
配置信息:JWT_AUTH到dev.py中
import datetimeJWT_AUTH = { # 过期时间 'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1), # 自定义认证结果:见下方序列化user和自定义response 'JWT_RESPONSE_PAYLOAD_HANDLER': 'user.utils.jwt_response_payload_handler', }
序列化user:user/serializers.py(自己创建)
from rest_framework import serializersfrom .models import Userclass UserModelSerializer(serializers.ModelSerializer): """轮播图序列化器""" class Meta: model = User fields = ["username", "mobile"]
自定义response:user/utils.py
from .serializers import UserModelSerializersdef jwt_response_payload_handler(token, user=None, request=None): return { 'token': token, 'user': UserModelSerializer(user).data } # restful 规范 # return { # 'status': 0, # 'msg': 'OK', # 'data': { # 'token': token, # 'username': user.username # } # }
基于drf-jwt的全局认证:user/authentications.py(自己创建)
import jwtfrom rest_framework.exceptions import AuthenticationFailedfrom rest_framework_jwt.authentication import jwt_decode_handlerfrom rest_framework_jwt.authentication import get_authorization_headerfrom rest_framework_jwt.authentication import BaseJSONWebTokenAuthenticationclass JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication): def authenticate(self, request): # 采用drf获取token的手段 - HTTP_AUTHORIZATION - Authorization token = get_authorization_header(request) if not token: raise AuthenticationFailed('Authorization 字段是必须的') # 可以添加反扒措施:原功能是token有前缀 # drf-jwt认证校验算法 try: payload = jwt_decode_handler(token) except jwt.ExpiredSignature: raise AuthenticationFailed('签名过期') except jwt.InvalidTokenError: raise AuthenticationFailed('非法用户') user = self.authenticate_credentials(payload) # 将认证结果丢该drf return user, token
全局启用:settings/dev.py
REST_FRAMEWORK = { # 认证模块 'DEFAULT_AUTHENTICATION_CLASSES': ( 'user.authentications.JSONWebTokenAuthentication', ),}
局部启用禁用:任何一个cbv类首行
# 局部禁用authentication_classes = []# 局部启用from user.authentications import JSONWebTokenAuthenticationauthentication_classes = [JSONWebTokenAuthentication]
多方式登录:user/utils.py
from django.contrib.auth.backends import ModelBackendfrom .models import Userimport reclass JWTModelBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): """ :param request: :param username: 前台传入的用户名 :param password: 前台传入的密码 :param kwargs: :return: """ try: if re.match(r'^1[3-9]\d{9}$', username): user = User.objects.get(mobile=username) elif re.match(r'.*@.*', username): user = User.objects.get(email=username) else: user = User.objects.get(username=username) except User.DoesNotExist: return None # 认证失败就返回None即可,jwt就无法删除token # 用户存在,密码校验通过,是活着的用户 is_active字段为1 if user and user.check_password(password) and self.user_can_authenticate(user): return user # 认证通过返回用户,交给jwt生成token
配置多方式登录:settings/dev.py
AUTHENTICATION_BACKENDS = ['user.utils.JWTModelBackend']
手动签发JWT:了解 - 可以拥有原生登录基于Model类user对象签发JWT
from rest_framework_jwt.settings import api_settingsjwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLERjwt_encode_handler = api_settings.JWT_ENCODE_HANDLERpayload = jwt_payload_handler(user)token = jwt_encode_handler(payload)# 了解,原生视图# 原生APIView可以实现手动签发 jwtclass LoginAPIView(APIView): def post(self): # 完成手动签发 pass