【一】simple-jwt快速使用
1)安装
pip install djangorestframework-simplejwt
2)使用
1.签发
-
路由 配置
from django.urls import path from rest_framework_simplejwt.views import token_obtain_pair urlpatterns = [ path('login/', token_obtain_pair) ]
2.认证
-
视图类
from rest_framework.permissions import IsAuthenticated from rest_framework_simplejwt.authentication import JWTTokenUserAuthentication class UserAPIView(APIView): # 认证 authentication_classes = [JWTAuthentication] # 权限 permission_classes = [IsAuthenticated] def get(self, request): return Response('已登陆')
-
使用
- 在 请求头 内添加:
{Authorization":"Bearer+空格+返回的access内容"}
3.补充
-
如果不加权限
- 携带了token,就进行校验;未携带token,不进行认证校验
-
返回的
refresh
有效时间长,access
有效时间短,access
是由refresh
生成而来- 每次签发都会更新
refresh
与access
【二】simple-jwt的配置文件
1)Simple JWT的默认配置
# JWT配置
SIMPLE_JWT = {
# Access Token的有效期
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
# Refresh Token的有效期
'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
# 对于大部分情况,设置以上两项就可以了,以下为默认配置项目,可根据需要进行调整
# 是否自动刷新Refresh Token
'ROTATE_REFRESH_TOKENS': False,
# 刷新Refresh Token时是否将旧Token加入黑名单,如果设置为False,则旧的刷新令牌仍然可以用于获取新的访问令牌。需要将'rest_framework_simplejwt.token_blacklist'加入到'INSTALLED_APPS'的配置中
'BLACKLIST_AFTER_ROTATION': False,
'ALGORITHM': 'HS256', # 加密算法
'SIGNING_KEY': settings.SECRET_KEY, # 签名密匙,这里使用Django的SECRET_KEY
# 如为True,则在每次使用访问令牌进行身份验证时,更新用户最后登录时间
"UPDATE_LAST_LOGIN": False,
# 用于验证JWT签名的密钥返回的内容。可以是字符串形式的密钥,也可以是一个字典。
"VERIFYING_KEY": "",
"AUDIENCE": None,# JWT中的"Audience"声明,用于指定该JWT的预期接收者。
"ISSUER": None, # JWT中的"Issuer"声明,用于指定该JWT的发行者。
"JSON_ENCODER": None, # 用于序列化JWT负载的JSON编码器。默认为Django的JSON编码器。
"JWK_URL": None, # 包含公钥的URL,用于验证JWT签名。
"LEEWAY": 0, # 允许的时钟偏差量,以秒为单位。用于在验证JWT的过期时间和生效时间时考虑时钟偏差。
# 用于指定JWT在HTTP请求头中使用的身份验证方案。默认为"Bearer"
"AUTH_HEADER_TYPES": ("Bearer",),
# 包含JWT的HTTP请求头的名称。默认为"HTTP_AUTHORIZATION"
"AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
# 用户模型中用作用户ID的字段。默认为"id"。
"USER_ID_FIELD": "id",
# JWT负载中包含用户ID的声明。默认为"user_id"。
"USER_ID_CLAIM": "user_id",
# 用于指定用户身份验证规则的函数或方法。默认使用Django的默认身份验证方法进行身份验证。
"USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",
# 用于指定可以使用的令牌类。默认为"rest_framework_simplejwt.tokens.AccessToken"。
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
# JWT负载中包含令牌类型的声明。默认为"token_type"。
"TOKEN_TYPE_CLAIM": "token_type",
# 用于指定可以使用的用户模型类。默认为"rest_framework_simplejwt.models.TokenUser"。
"TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",
# JWT负载中包含JWT ID的声明。默认为"jti"。
"JTI_CLAIM": "jti",
# 在使用滑动令牌时,JWT负载中包含刷新令牌过期时间的声明。默认为"refresh_exp"。
"SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
# 滑动令牌的生命周期。默认为5分钟。
"SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
# 滑动令牌可以用于刷新的时间段。默认为1天。
"SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),
# 用于生成访问令牌和刷新令牌的序列化器。
"TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",
# 用于刷新访问令牌的序列化器。默认
"TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer",
# 用于验证令牌的序列化器。
"TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer",
# 用于列出或撤销已失效JWT的序列化器。
"TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer",
# 用于生成滑动令牌的序列化器。
"SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer",
# 用于刷新滑动令牌的序列化器。
"SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer",
}
2)自定义配置方式
-
setting.py
from datetime import timedelta SIMPLE_JWT={ # Access Token的有效期 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60), # Refresh Token的有效期 'REFRESH_TOKEN_LIFETIME': timedelta(days=7), }
【三】定制返回格式
-
新建文件
rewrite_jwt.py
-
重写
validate
,返回的内容就是更改的格式from rest_framework_simplejwt.serializers import TokenObtainPairSerializer class FormatToken(TokenObtainPairSerializer): def validate(self, attrs): old_data = super().validate(attrs) data = {'code': 100, 'msg': '登录成功成功', 'username': self.user.username, 'refresh': old_data.get('refresh'), 'access': old_data.get('access'), } return data
-
全局配置
SIMPLE_JWT = { "TOKEN_OBTAIN_SERIALIZER": "App.tool.rewrite_jwt.FormatToken", }
【四】更改载荷
-
与定制类似
-
在validate的序列化类内重写一个类方法,返回的内容就是重写的载荷
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer class FormatToken(TokenObtainPairSerializer): @classmethod def get_token(cls, user): token = super().get_token(user) token['username'] = user.username return token def validate(self, attrs): ...... return data
【五】扩写auth的user表
-
尽量在未迁移之前扩写
- 删库,删迁移文件
- (app内migrations的新增文件、django内置app的admin与auth)
-
配置文件
AUTH_USER_MODEL='App文件名.新的表名'
【六】多方式登录
-
系列化类
from rest_framework import serializers from rest_framework_simplejwt.tokens import RefreshToken # 只用于校验 class LoginSerializer(serializers.Serializer): username = serializers.CharField() password = serializers.CharField() def validate(self, attrs): # 获取前端传入的信息 username = attrs.get('username') password = attrs.get('password') # 正则判断登录方式 import re from django.contrib.auth.models import User if re.match(r'^1[3-9][0-9]{9}$', username): # 手机登录 user = User.objects.filter(mobile=username).first() elif re.match(r'^.+@.+$', username): # 邮箱登录 user = User.objects.filter(email=username).first() else: # 账号登录 user = User.objects.filter(username=username).first() # 校验密码 if user and user.check_password(password): refresh = RefreshToken.for_user(user) self.context['refresh'] = str(refresh) self.context['access'] = str(refresh) print(self.context) return attrs else: raise '用户名或密码错误'
-
视图类
class LoginAPIView(APIView): def post(self, request): serializer = LoginSerializer(data=request.data) serializer.is_valid(raise_exception=True) refresh = serializer.context['refresh'] access = serializer.context['access'] return Response({'code': 100, 'mas': '登录成功', 'refresh': refresh, 'access': access})
【七】自定义用户表 的签发、认证
1)签发
-
序列化类
class LoginSerializer(serializers.Serializer): username = serializers.CharField() password = serializers.CharField() def validate(self, attrs): # 获取前端传入的信息 username = attrs.get('username') password = attrs.get('password') # 选择用户表进行校验 user = User.objects.filter(username=username).first() if user and user.check_password(password): refresh = RefreshToken.for_user(user) self.context['refresh'] = str(refresh) self.context['access'] = str(refresh) return attrs else: raise '用户名或密码错误'
-
视图类
class LoginAPIView(APIView): def post(self, request): serializer = LoginSerializer(data=request.data) serializer.is_valid(raise_exception=True) refresh = serializer.context['refresh'] access = serializer.context['access'] return Response({'code': 100, 'mas': '登录成功', 'refresh': refresh, 'access': access})
2)认证
-
新建文件
auth.py
-
重写
authenticate
from rest_framework.authentication import BaseAuthentication from rest_framework_simplejwt.tokens import AccessToken from rest_framework.authtoken.admin import User class JsonWebTokenCommonAuthentication(BaseAuthentication): def authenticate(self, request): token = request.META.get('HTTP_AUTHORIZATION') if token: # 获取载荷的数据 res = AccessToken(token=token) user_id = res['user_id'] user = User.objects.get(pk=user_id) return user,token else: raise '未携带认证信息'
-
使用
class UserAPIView(APIView): # 自定义认证 from App.tool.auth import JsonWebTokenCommonAuthentication authentication_classes = [JsonWebTokenCommonAuthentication] def get(self, request): return Response('已登陆')