Django-rest-framework JWT认证
一.JWT 介绍
- Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519)
- 该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景
- JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源
- 也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密
二.JWT认证与session认证的区别
1.基于session认证流程图
服务器需要存储用户的token信息
2.基于jwt认证流程图
服务端不需要存储用户token, 都存在客户端
三.JWT 的构成
JWT就是一段字符串, 由三段信息构成, 三段信息文本使用.
(点) 拼接就构成了JWT字符串 :
eyJhbGciOiJIUzI1sNiIsIn.eyJzdWIiOiIxMjRG9OnRydWV9.TJVArHDcEfxjoYZgeFONFh7HgQ
- 第一部分我们称它为头部 :
header
- 第二部分我们称其为载荷 :
payload
(类似于飞机上承载的物品) - 第三部分是签证 :
signature
1.头部 : header
两部分组成 :
- 声明类型(当前令牌名称)
- 声明加密算法
{
'typ': 'JWT',
'alg': 'HS256'
}
将头部使用
base64
编码构成第一部分 (下面介绍base64编码方法, 该编码可以对称解码)
eyJ0eXAiOiJKV1iIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiQiLCJhbGciO
2.载荷 : payload
存放用户有效信息的地方, JWT 规定了7个官方字段, 可以选用
iss (issuer)
:签发人exp (expiration time)
:过期时间sub (subject)
:主题aud (audience)
:受众nbf (Not Before)
:生效时间iat (Issued At)
:签发时间jti (JWT ID)
:编号
除了上面的字段, 你自己也可以添加自己想要的字段, 需要注意的是:这些信息是不加密的, 所以最好不要存敏感信息
{
"sub": "1234567890",
"name": "John Doe",
"age": 23
"admin": true
}
将载荷使用
base64
编码构成第二部分
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
3.签名 : signatrue
signature 由三部分构成 :
- base64 编码后的 header
- base64 编码后的 payload
- secret : 秘钥 (只有服务端知道)
# 使用header中指定的加密算法将三个信息以下面的方式进行加密
string = [base64 编码后的 header] + "." + [base64 编码后的 payload] # 字符串拼接
HMACSHA256(string, secret) # 加密算法加密得到加密摘要(TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONF)
4.得到 token
算出签名之后, 把 header、payload、signatrue 三部分使用 .
(点) 拼接成一个大字符串, 然后返回给客户端让其存储
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
注意 :
- secret是保存在服务器端的, jwt的签发生成也是在服务器端的
- secret就是用来进行jwt的签发和jwt的验证, 所以, 它就是你服务端的私钥
- 在任何场景都不应该流露出去, 一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了
四.base64 编码和解码的使用
首先 base64 是一种编码方式, 并非加密方式; 它跟语言无关, 任何语言都能使用 base64 编码&解码
1.base64 编码
import base64
import json
# 定义一个信息字段
dic = {"id": 1, "name": "shawn", "age": "male"}
# 将其序列化成json格式字符串
json_str = json.dumps(dic)
# 将json格式字符串encode再使用base64编码成一串Bytes格式编码
base64_bytes = base64.b64encode(json_str.encode('utf-8'))
print(base64_bytes)
# b'eyJpZCI6IDEsICJuYW1lIjogInNoYXduIiwgImFnZSI6ICJtYWxlIn0='
print(base64_bytes.decode('utf-8'))
# eyJpZCI6IDEsICJuYW1lIjogInNoYXduIiwgImFnZSI6ICJtYWxlIn0=
得到的字符串后面有等号, 代表不是 4 的倍数使用等号填充
2.base64 解码
import base64
import json
bytes_str = b'eyJpZCI6IDEsICJuYW1lIjogInNoYXduIiwgImFnZSI6ICJtYWxlIn0='
res = base64.b64decode(bytes_str)
print(res) # b'{"id": 1, "name": "shawn", "age": "male"}'
五.JWT 的原理
JWT的本质原理就是签发和校验 : 关于签发和核验JWT, 我们可以使用Django REST framework JWT扩展来完成
1.签发
根据登录请求提交来的 账号 + 密码 + 设备信息 签发 token
- 用基本信息存储 json 字典, 采用 base64 编码得到头字符串
- 用关键信息存储 json 字典,采用 base64 编码得到体字符串
- 用头、体编码的字符串再加安全码信息(secret)存储 json 字典, 采用 header 中指定的算法加密得到签名字符串
2.校验
根据客户端带 token 的请求 反解出 user 对象
- 将 token 按
.
(点) 拆分为三段字符串, 第一段编码后的头字符串一般不需要做任何处理 - 第二段编码后的体字符串, 要解码出用户主键, 通过主键从 User 表中就能得到登录用户, 过期时间和设备信息都是安全信息, 确保 token 没过期, 且是同一设备来的
- 再将第一段 + 第二段 + 服务器安全码使用header中指定的不可逆算法加密, 与第三段 签名字符串进行对比校验, 通过后才能代表第二段校验得到的 user 对象就是合法的登录用户
六.DRF 项目的 JWT 认证开发流程
- 用账号密码访问登录接口, 登录接口逻辑中调用签发 token 算法, 得到 token, 返回给客户端, 客户端自己存到 cookies 中 (上面有流程图介绍)
- 校验 token 的算法应该写在认证类中(在认证类中调用), 全局配置给认证组件, 所有视图类请求, 都会进行认证校验, 所以请求带了 token, 就会反解出 user 对象, 在视图类中用 request.user 就能访问登录的用户
ps : 登录接口需要做 认证 + 权限 两个局部禁用
七. drf-jwt 的安装和基本使用
JWT的本质原理就是签发和校验 : 关于签发和核验JWT, 我们可以使用Django REST framework JWT扩展来完成
1.官网下载
?GitHub : https://github.com/jpadilla/django-rest-framework-jwt
2.pip 安装
pip install djangorestframework-jwt
3.简单使用
- 简单使用 : 自动签发 token 和自动认证
# 默认使用的是 auth 的 user 表
# 不需要书写登入功能以及认证类, jwt都内置了
- 先在
auth_user
中创建一个用户
# 终端
manage.py@jwt_test > createsuperuser
用户名 : ...
邮箱 : 直接回车跳过
密码: ...
确认密码: ...
- urls.py
from django.contrib import admin
from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token # 就是一个视图函数
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', obtain_jwt_token), # jwt提供的认证
]
- Postman 中进行测试
提交数据, jwt 认证进行校验并签发 token, 返回客户端
obtain_jwt_token
的本质, 我们可以 Ctrl+点击 进入源码查看
# 所以说它本质就是一个视图类, 我们也可以这样填写?
path('login/', ObtainJSONWebToken.as_view()),
4.djangorestframework-jwt 的默认配置文件
# djangorestframework-jwt也有配置文件,也有默认配置
# 默认过期时间是 5 分钟 (可以进行配置)
# settings.py 文件
import datatime
JWT_AUTH = {
# 自定义过期时间1天
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
# 也可以自定义认证结果reaponse (下面介绍)
# 如果不自定义, 返回的格式是固定的, 只有token字段(如上面演示所看到的)
'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.custom_jwt_response_payload_handler',
}
八.JWT 实现自动签发 token, 自定义响应格式, 限制某接口登入后访问
1.需求
- 使用 jwt 内置登入认证, 但自定义 response 内的信息
- 限制查询图书接口必须登录才能用 (加在视图类中)
2.书写自定义响应格式
- 我们可以先查看默认的 jwt 响应
# 导入 jwt 响应, Ctrl+点击 进入源码查看
from rest_framework_jwt.utils import jwt_response_payload_handler
我们直接 copy 过来修改
- myresponse.py
# 重写该响应
def custom_jwt_response_payload_handler(token, user=None, request=None):
return {
'status': 200,
'messages': 'success!',
'user_id': user.id,
'username': user.username,
'token': token
}
3.自定义 djangorestframework-jwt 配置
- settings.py
import datatime
JWT_AUTH = {
# 自定义过期时间7天
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
# 指定自己重写的 jwt 响应
'JWT_RESPONSE_PAYLOAD_HANDLER': 'drf_test.myresponse.custom_jwt_response_payload_handler',
}
4.书写其他文件逻辑
- models.py
# 创建建书籍表,并自行添加书籍
from django.db import models
class Book(models.Model):
name = models.CharField(max_length=32)
price = models.IntegerField()
- serializer.py
from rest_framework import serializers
from drf_test import models
# 创建一个书籍的序列化类
class BookModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = "__all__"
extra_kwargs = {
'title': {
'help_text': '这是书籍的名字!!'
}
}
- views.py
from drf_test import serializer
from drf_test import models
from rest_framework.viewsets import ModelViewSet
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.pagination import PageNumberPagination
PageNumberPagination.page_size = 2 # 设置分页的单页显示条数
class BookView(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
pagination_class = PageNumberPagination
# 如果使用jwt内置的认证类, 需要配合一个权限类
# 因为只加认证类, 只要带了token, 就认证, 不带token就不认证
# 所以就算你不带token也可以查到书籍,这不是我们想要的效果
authentication_classes = [JSONWebTokenAuthentication, ]
# 判断当前登录用户是否通过了认证(需要配合这个权限类)
permission_classes = [IsAuthenticated, ]
def list(self, request, *args, **kwargs):
print(request.user)
return super().list(request, *args, **kwargs)
5.测试效果
- 自定义响应测试
- 测试认证通过后能访问书籍, 不通过无法访问
6.头部访问格式
- 上面测试注意事项 : token 放在
Headers
中, 并且 Key 为Authorization
(源码里规定这么写的)
- 使用 jwt 内置的认证, 如果没有修改配置文件中配置的前缀, 那么
jwt
前缀(大小写都行)必须要加, 如果不加前缀认证就返回 None, 认证就失效了
# 格式
Authorization:JWT [三段式的 token] # jwt + 空格 + token,源码里是以空格切分
- 也可以修改认证前缀
JWT_AUTH = {
'JWT_RESPONSE_PAYLOAD_HANDLER': 'drf_test.myresponse.custom_jwt_response_payload_handler',
'JWT_AUTH_HEADER_PREFIX': 'MYJWT', # 了解一下就行, 一般不改
}
九.源码Copy+修改实现自定义认证类
1.jwe 自带认证类源码
- 上面的实战例子我们使用的是 jwt 自带的认证类, 如果我们要自己手动写, 就必须重写
authenticate
方法, 我们看看其源码的逻辑:
2.自定义认证类
- 自建一个 auth 认证类文件书写
import jwt
from drf_test import models
from rest_framework import exceptions
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework_jwt.settings import api_settings
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
'''
JWT_DECODE_HANDLER 在源码中所对应的方法:'rest_framework_jwt.utils.jwt_decode_handler'
将该方法内存地址赋值给:jwt_decode_handler
'''
# 继承JSONWebTokenAuthentication类来书写
class CustomJsonAuthentication(JSONWebTokenAuthentication):
# 认证类必须重写 authenticate 方法
def authenticate(self, request):
# 1.获取到request中的token
jwt_value = self.get_jwt_value(request)
# 2.也可以直接将token放在url中使用get来获取(但一般不这么做)
# jwt_value = self.request.GET.get('token')
# 3.还可以从META中获取
# jwt_value = request.META.get('HTTP_AUTHORIZATION')
if jwt_value:
# 验证签名
try:
# 得到荷载
payload = jwt_decode_handler(jwt_value)
# 直接从数据库中找出用户对象(每次都要查询数据库,消耗大,并且并不是所有字段都需要)
# user_obj = models.User.objects.filter(id=payload['user_id']).first()
# 可以临时生成一个只有id和username的对象,只有需要的时候才拿出id或username去数据库中过滤用户
user_obj = models.User(id=payload['user_id'],username=payload['username'])
# 又或者直接使用字典的方式(能取出值就ok)
# user_obj = {'id':payload['user_id'],'username':payload['username']}
except jwt.ExpiredSignature:
raise exceptions.AuthenticationFailed('token已过期')
except jwt.DecodeError:
raise exceptions.AuthenticationFailed('签名错误')
except jwt.InvalidTokenError as e:
raise exceptions.AuthenticationFailed(e)
return user_obj,jwt_value
raise exceptions.AuthenticationFailed('请携带token进行认证!')
3.在视图中使用自定义的认证类
- views.py
from drf_test import serializer
from drf_test import models
from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination
PageNumberPagination.page_size = 2
# 导入自定义的认证类
from drf_test.auth.customauth import CustomJsonAuthentication
class BookView(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
pagination_class = PageNumberPagination
# 自己写的认证类
authentication_classes = [CustomJsonAuthentication,]
def list(self, request, *args, **kwargs):
print(request.user)
return super().list(request, *args, **kwargs)
4.测试效果
- 不携带 token
- 提供错误的 token
- 验证通过
十.自定义登入并签发 token
1.签发 token 源码分析
- 如果我们要实现自定义的 token 签发就必须了解 jwt token签发的原理
- 前面我们自定义响应格式的时候返回了一个 token,这里已经有 token,那么 token 是在哪里产生的呢?
- 我们猜想应该是request传进来到序列化类进行校验, 校验成功后就签发 token 的
- 查看 jwt 的序列化类
- jwt_payload_handler 源码分析
# 导入该方法 Ctrl + 点击 进入
from rest_framework_jwt.utils import jwt_payload_handler
- jwt_encode_handler 源码分析
2.自定义签发 token
- 将 auth_user 表该个名, 自己新建个 User 表方便实验 (models.py)
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
phone = models.BigIntegerField(null=True)
class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
存入用户名和密码
- views.py
from rest_framework.response import Response
from rest_framework.views import APIView
# 导入 jwt 配置文件
from rest_framework_jwt.settings import api_settings
# 将获取 payload 的方法以及签发 token 的方法内存地址赋值给两个变量
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class UserLoginView(APIView):
def post(self, request, *args, **kwargs):
username = request.data.get('username')
password = request.data.get('password')
user = models.User.objects.filter(username=username, password=password).first()
if user:
# 调用两个方法签发 token
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return Response({'status': 200, 'msg': '登入成功!', 'token': token})
else:
return Response({'status': 201, 'msg': '用户名或密码错误!'})
- urls.py
path('login2/', views.UserLoginView.as_view()),
3.测试效果
- 用户名或密码错误测试
- 登入成功测试
4.自定义token认证(方便以后copy版)
"""
常用的认证以及DRF的认证
"""
from dimension import models
import jwt
from rest_framework import exceptions
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import jwt_decode_handler
from django.conf import settings
from django.contrib.auth import get_user_model
from six import text_type
from django.utils.translation import ugettext as _
from rest_framework import exceptions
from rest_framework_jwt.utils import jwt_decode_handler
User = get_user_model()
class OpAuthJwtAuthentication(object):
"""
统一JWT认证
"""
def authenticate(self, request):
token = self.get_header_authorization(request) or self.get_cookie_authorization(request)
if not token:
raise AuthenticationFailed('当前用户未登录,请登录!')
try:
payload = jwt_decode_handler(token)
except jwt.ExpiredSignature:
msg = _('会话过期,请重新登录!')
raise exceptions.AuthenticationFailed(msg)
except jwt.DecodeError:
msg = _('签名错误,请重试!')
raise exceptions.AuthenticationFailed(msg)
except jwt.InvalidTokenError:
raise exceptions.AuthenticationFailed()
except User.DoesNotExist:
raise exceptions.AuthenticationFailed()
user_id = payload.get('user_id', None)
if not user_id:
return None
user_id_field = settings.USER_FIELD or 'user_id'
user = User.objects.filter(**{user_id_field: user_id}).first()
if not user or not user.is_active:
return None
return user, token
def authenticate_header(self, request):
pass
@classmethod
def get_header_authorization(cls, request):
"""
获取header里的认证信息, 通常用于跨域携带请求
:param request:
:return:
"""
auth = request.META.get('HTTP_AUTHORIZATION', b'')
if isinstance(auth, text_type):
auth = auth.encode(settings.JWT_AUTH.get('HTTP_HEADER_ENCODING', 'iso-8859-1'))
if not auth:
return ''
auth = str(auth, encoding='utf-8').split()
if len(auth) != 2 or auth[0].upper() != settings.JWT_AUTH.get('JWT_AUTH_HEADER_PREFIX', 'JWT').upper():
return ''
return auth[1]
@classmethod
def get_cookie_authorization(cls, request):
"""
获取cookie里JWT认证信息
:param request:
:return:
"""
auth = request.COOKIES.get(settings.JWT_AUTH.get('JWT_AUTH_COOKIE', 'AUTH_JWT'), '')
auth = auth.split()
if len(auth) != 2 or auth[0].upper() != settings.JWT_AUTH.get('JWT_AUTH_HEADER_PREFIX', 'JWT'):
return ''
return auth[1]
class JsonAuthentication(JSONWebTokenAuthentication):
def authenticate(self, request):
jwt_value = self.get_jwt_value(request)
if not jwt_value:
raise AuthenticationFailed('当前用户未登录,请登录!')
# 验证签名,验证是否过期
try:
# 得到荷载
payload = jwt_decode_handler(jwt_value)
# 效率更高一写,不需要查数据库了
user = models.User(user_id=payload['user_id'])
except jwt.ExpiredSignature:
msg = '会话过期,请重新登录!'
raise exceptions.AuthenticationFailed(msg)
except jwt.DecodeError:
msg = '签名错误,请重试!'
raise exceptions.AuthenticationFailed(msg)
except jwt.InvalidTokenError:
raise exceptions.AuthenticationFailed("签名验证错误,非法用户")
return (user, jwt_value)
十一.实现多方式登入, 并将逻辑写在序列化类中
1.需求
- 登入方式多种 : (用户名、输入手机号、 输入邮箱) + 密码
- 逻辑书写在序列化类中
2.代码实现
- serializer.py
from django.db.models import Q # 用来构建或与非
from rest_framework.exceptions import ValidationError
# 导入 jwt 配置文件
from rest_framework_jwt.settings import api_settings
# 将获取 payload 的方法以及签发 token 的方法内存地址赋值给两个变量
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
# 多登入方式序列化类
class VariousLoginModelSerializer(serializers.ModelSerializer):
# 重写 username 字段让其时区字段自己的校验规则, 不然会出现required错误
username = serializers.CharField()
class Meta:
model = models.UserInfo
fields = ['username', 'password']
def validate(self, attrs):
username = attrs.get('username')
password = attrs.get('password')
# 多登入方式,username可能是用户名、邮箱、手机号,分情况操作
if username.isdigit():
user = models.UserInfo.objects.filter(Q(phone=int(username))).first()
else:
user = models.UserInfo.objects.filter(Q(email=username) | Q(username=username)).first()
if user and user.check_password(password):
# 登入成功,签发token
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
# context是上下文,是视图类和序列化类沟通的桥梁(管道)
self.context['token'] = token
self.context['username'] = username
self.context['user_obj'] = user # 将当前user对象也放进去
return attrs
else:
raise ValidationError('用户名或密码错误!!')
- views.py
from rest_framework.generics import CreateAPIView
from drf_test import models
from drf_test import serializer
from rest_framework.response import Response
from rest_framework.viewsets import ViewSetMixin
# 多种登入方式(继承ViewSetMixin自动生成路由)
class VariousLoginView(ViewSetMixin, CreateAPIView):
queryset = models.UserInfo.objects.all()
serializer_class = serializer.VariousLoginModelSerializer
def create(self, request, *args, **kwargs):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
# 从 context 中取出序列化类传过来的数据
token = ser.context['token']
username = ser.context['username']
user_obj = ser.context['user_obj'] # 拿到user对象
return Response({'status': 200, 'msg': '登入成功!!', 'token': token, 'username': user_obj.username})
else:
return Response({'status': 100, 'msg': ser.errors})
3.效果演示
- 用户名登入
- 邮箱登入
- 手机号登入
4.使用正则来匹配是哪种登入方式
- 只需要改写序列化类中的用户查询的代码
class VariousLoginModelSerializer(serializers.ModelSerializer):
# 重写 username 字段让其时区字段自己的校验规则, 不然会出现required错误
username = serializers.CharField()
class Meta:
model = models.UserInfo
fields = ['username', 'password']
def validate(self, attrs):
username = attrs.get('username')
password = attrs.get('password')
# 多登入方式,username可能是用户名、邮箱、手机号,分情况操作
if re.match('^1[3-9][0-9]{9}$', username):
# 用手机号登录
user = models.UserInfo.objects.filter(phone=username).first()
elif re.match(r'^.+@.+$', username): # 这里匹配不严谨(仅用于测试)
# 以邮箱登录
user = models.UserInfo.objects.filter(email=username).first()
else:
# 以用户名登录
user = models.UserInfo.objects.filter(username=username).first()
if user and user.check_password(password):
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
self.context['token'] = token
self.context['username'] = username
self.context['user_obj'] = user
return attrs
else:
raise ValidationError('用户名或密码错误!!')
十二.实现token续签
视图view.py:
class RefreshJSONWebTokenView(JSONWebTokenAPIView):
'''
刷新token接口
'''
def post(self, request, *args, **kwargs):
serializer_class = RefreshJSONWebTokenSerializer(data=request.data)
if serializer_class.is_valid(raise_exception=True):
return SuccessResponse(data=serializer_class.data)
else:
return ErrorResponse(msg="会话过期,请重试!")
序列化serializer.py:
from rest_framework_jwt.serializers import VerificationBaseSerializer
class RefreshJSONWebTokenSerializer(VerificationBaseSerializer):
'''
刷新token
'''
def validate(self, attrs):
token = attrs['token']
payload = self._check_payload(token=token)
user = self._check_user(payload=payload)
# Get and check 'orig_iat'
orig_iat = payload.get('orig_iat')
if orig_iat:
refresh_limit = api_settings.JWT_REFRESH_EXPIRATION_DELTA
if isinstance(refresh_limit, timedelta):
refresh_limit = (refresh_limit.days * 24 * 3600 +
refresh_limit.seconds)
expiration_timestamp = orig_iat + int(refresh_limit)
now_timestamp = timegm(datetime.datetime.utcnow().utctimetuple())
if now_timestamp > expiration_timestamp:
msg ='会话已经过期,请重试!'
raise serializers.ValidationError(msg)
else:
msg = '签名错误,请重试!'
raise serializers.ValidationError(msg)
# 设置刷新的token 有效期为7天
settings.JWT_AUTH["JWT_EXPIRATION_DELTA"] = datetime.timedelta(days=7)
api_setting = APISettings(USER_SETTINGS, DEFAULTS, IMPORT_STRINGS)
jwt_payload = api_setting.JWT_PAYLOAD_HANDLER
jwt_encode = api_setting.JWT_ENCODE_HANDLER
new_payload = jwt_payload(user)
new_payload['orig_iat'] = orig_iat
token = jwt_encode(new_payload)
return {
'token': token,
'user': user
}
版权声明:
作者:淘小欣
链接:https://blog.taoxiaoxin.club/181.html
来源:淘小欣的博客
文章版权归作者所有,未经允许请勿转载。

共有 0 条评论