简介
生成token, 就是把 某个东西 以某个key值(密钥) 加密 一下
简单的生成token举例
下面用python举例一下
# 安装
pip install pyjwt==1.7.1 (新版本的不行)
输入python,在python解析器里,运行生成token(要传payload参数,和key)
import jwt
paylod={"name":"taoker111"}
token =jwt.encode(payload=paylod,key="tk123")
# 解码 得到payload
# jwt.decode(token,key="123")
Django_rf的simplejwt
Django 3.1 版本之前是使用rest_framework_jwt
库, 之后版本的django会遇到这个报错
Could not import 'rest_framework_jwt.authentication.JSONWebTokenAuthentication' for API setting 'DEFAULT_AUTHENTICATION_CLASSES'. ImportError: cannot import name 'smart_text' from 'django.utils.encoding'
djangorestframework-simplejwt
库提供了与 rest_framework_jwt
类似的 JSON Web Token (JWT) 认证功能。
1.安装
djangorestframework-simplejwt
库(如果尚未安装):
pip install djangorestframework-simplejwt
2.JWT 库默认的参数
djangorestframework-simplejwt
默认使用一组默认值,但你可以根据需要设置这些参数。
如:
- 默认token有效期为 5分钟
- 生成token密钥SIGNING_KEY默认为 :setting.py 中, 创建项目就生成好了的一个 key值
- 参数:AUTH_HEADER_TYPES 指定前缀,默认为Bearer
(from rest_framework_simplejwt.settings import )这么写然后点击settings
如下是AUTH_HEADER_TYPES 前缀的意思,如果不配置,就是 Bearer开头
(后续可以登录成功后的access)使用pyjwt库来,用你的key来解码试试,它的信息包含这些
{'token_type': 'access', 'exp': 1689661573, 'iat': 1689661513, 'jti': 'eedea8e9d74b4da8b9e1932624952ee8', 'user_id': 3}
自定义配置JWT
djangorestframework-simplejwt
默认使用一组安全的默认值,但你可以根据需要设置这些参数。例如,你可以在 settings.py
中添加以下配置:
# settings.py
from datetime import timedelta
SIMPLE_JWT = {
"AUTH_HEADER_TYPES": ("JWT",), # 指定前缀
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60), # 访问令牌过期时间
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1), # 滑动刷新令牌的过期时间
'SLIDING_TOKEN_REFRESH_LIFETIME_GRACE_PERIOD': timedelta(minutes=5), # 滑动刷新令牌宽限期
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp', # 滑动刷新令牌的过期时间声明名称
}
直接使用写登录
(不改默认的序列化器 和 视图)
自带了 登录视图类 TokenObtainPairView 对应的序列化器TokenObtainSlidingSerializer
(from rest_framework_simplejwt.views import)
(from rest_framework_simplejwt.serializers import)
这么写可以进入到源码
(它的序列化器默认用到的是JWT 里的这个配置 TOKEN_OBTAIN_SERIALIZER,
即rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer)
利用本身的TokenObtainPairView 和 TokenObtainSlidingSerializer实现登录
直接把它配置到urls中,就能使用登录。
在外层urls.py中,配置
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)
urlpatterns = [
...
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'), # 用于获取
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), # 用于更新
path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'), # 未知
...
]
获取token
使用POST请求,json格式传递 账号 和密码
自定义登录接口:
第一步:重写序列化器
即TokenObtainPairSerializer,原有的获取token序列化器要修改下
from rest_framework_simplejwt.serializers import 这么写可以进入到源码)
token值中增加其他信息(不常用)
做法:
在system应用下,或users 应用 中 serializers.py 中
class LoginSerializer(TokenObtainPairSerializer):
"""
用户登录-序列化器(重写的)
"""
@classmethod
def get_token(cls, user):
token = super().get_token(user)
# Add custom claims
token['name'] = user.username
# ...
return token
先去完成第二步 (如前面已经配置了url,直接配置 SIMPLE_JWT)
"TOKEN_OBTAIN_SERIALIZER": "system.serializers.LoginSerializer",
登录查看效果,然后使用JWT解析,密钥在setting.py中。
于是access信息(下图的token2)中,就多了name的信息:
修改响应结构、补充字段等
- 序列化器:里面增加了user_info 用户信息( 这里的话,要配置setting,才生效)
如下是重写 获取token的序列化器
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from django.contrib.auth import authenticate
class LoginSerializer(TokenObtainPairSerializer):
# 可修改一些提示语
default_error_messages = {
'no_active_account': ('该账号已被禁用,请与管理员联系!')
}
# 响应中,增加了user_info字段, 增加了token字段
def validate(self, attrs):
data = super().validate(attrs)
authenticate_kwargs = {
self.username_field: attrs[self.username_field],
"password": attrs["password"],
}
self.user = authenticate(**authenticate_kwargs)
user = self.user
# 获取用户信息
user_info = {
'id': user.id,
'username': user.username,
'email': user.email,
# 添加其他用户信息...
}
# 补充一个token字段
data["token"] = data["access"]
# 将用户信息添加到响应数据中
data['user_info'] = user_info
return data
松勤:
是把它当模型序列化器来用,指定了model, fields字段,
并且重写validate,即序列化器里提到的校验方法,并定义响应格式,成功或失败的
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from django.contrib.auth import authenticate
from system.models import User
class LoginSerializer(TokenObtainPairSerializer):
class Meta:
model = User
fields = "__all__"
read_only_fields = ["id"]
default_error_messages = {
'no_active_account': ('该账号已被禁用,请与管理员联系!')
}
def validate(self, attrs):
username = attrs['username']
password = attrs['password']
user = User.objects.filter(username=username).first()
if not user:
result = {
"code": 400,
"msg": "账号或密码不正确!",
"data": None
}
return result
if user and not user.is_staff: # 判断是否允许登录后台
result = {
"code": 400,
"msg": "您没有权限登录后台!",
"data": None
}
return result
if user and not user.is_active:
result = {
"code": 400,
"msg": "该账号已被禁用,请与管理员联系!",
"data": None
}
return result
if user and user.check_password(password): # check_password() 对明文进行加密,并验证
data = super().validate(attrs)
refresh = self.get_token(self.user)
data['username'] = self.user.username
data['userId'] = self.user.id
data['refresh'] = str(refresh) # refresh_token
data['access'] = str(refresh.access_token) # access_token
request = self.context.get('request')
request.user = self.user
result = {
"code": 200,
"msg": "登录成功!",
"data": data
}
else:
result = {
"code": 400,
"msg": "账号或密码不正确!",
"data": None
}
return result
第二步:把重写的序列化器配置起来。
2. 视图类关联新定义的序列化器(假如已经在system应用下,serializers.py文件下重写好了)。
方式1:配置(TokenObtainPairView 视图类自己会找到它)
SIMPLE_JWT = {
# It will work instead of the default serializer(TokenObtainPairSerializer).
"TOKEN_OBTAIN_SERIALIZER": "system.serializers.LoginSerializer", # 应用.模块.类
# ...
}
方式2(推荐这个,这样代码可读性高点):views重写登录视图类,并指定自己写的序列化器、 url中改成用新的视图类
from apps.system.serializers import LoginSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
# 2.登录类
class LoginView(TokenObtainPairView):
serializer_class = LoginSerializer
url也配置在应用中(有更好的代码可读性)即可
认证方式设置为jwttoken认证
在 Django 的 settings.py
文件中进行设置认证方式中添加:JWTAuthentication:
# settings.py
REST_FRAMEWORK = {
# a.在全局指定默认的认证类(指定认证方式)
'DEFAULT_AUTHENTICATION_CLASSES': [
# 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', # 先进行token认证(Django 3.1 版本不能用了)
'rest_framework_simplejwt.authentication.JWTAuthentication',
# b.Session会话认证
'rest_framework.authentication.SessionAuthentication', # 次要进行session认证
'rest_framework.authentication.BasicAuthentication'
],
# 指定使用的权限类
# a.在全局指定默认的权限类(当认证通过之后,可以获取何种权限)
'DEFAULT_PERMISSION_CLASSES': [
# AllowAny 不管是否有认证成功,都能获取所有权限
# IsAdminUser 管理员(管理员需要登录)具备所有权限
# IsAuthenticated 只要登录,就具备所有权限
# IsAuthenticatedOrReadOnly,如果登录了就具备所有权限,不登录只具备读取数据的权限
'rest_framework.permissions.AllowAny',
],
# 其他设置...
}
假如不登录
登录,获取到token
其他接口中请求头中,传递Authorization,值默认为Bearer +空格 + 登录返回的access值
官方文档地址是:Simple JWT — Simple JWT 5.2.2.post27+g47b7a08 documentation
- 安装和配置
- JWT 认证的使用方法和示例
- 设置 JWT 认证的参数和选项
- 刷新令牌和滑动刷新令牌的使用
- 撤销令牌的使用方法
- JWT 认证视图
- 自定义认证逻辑
- 常见问题解答