DRF框架使用djangorestframework-simplejwt实现自定义用户类的token校验
1. 安装simplejwt库并修改settings.py
-
安装simplejwt
pip install djangorestframework pip install djangorestframework-simplejwt -
修改settings.py
-
注册应用
INSTALLED_APPS = [ ... 'rest_framework', 'rest_framework_simplejwt', ] -
设置jwt鉴权
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_simplejwt.authentication.JWTAuthentication', # 使用rest_framework_simplejwt(token)验证身份 ], 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated' # 设置全局所有视图需要jwt鉴权 ], } -
配置token相关参数(非必须,按需配置)
SIMPLE_JWT = { 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), # 可以修改这个值来改变token的过期时间 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), 'ROTATE_REFRESH_TOKENS': True, 'BLACKLIST_AFTER_ROTATION': True, 'ALGORITHM': 'HS256', # 对称算法:HS256 HS384 HS512 非对称算法:RSA 'SIGNING_KEY': SECRET_KEY, 'VERIFYING_KEY': None, # if signing_key, verifying_key will be ignore. 'AUDIENCE': None, 'ISSUER': None, 'AUTH_HEADER_TYPES': ('Bearer',), # Authorization: Bearer <token> 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION', # if HTTP_X_ACCESS_TOKEN, X_ACCESS_TOKEN: Bearer <token> 'USER_ID_FIELD': 'id', # 使用唯一不变的数据库字段,将包含在生成的令牌中以标识用户 'USER_ID_CLAIM': 'user_id', } -
连接数据库
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'testdb', 'USER': 'root', 'PASSWORD': 'xxxxxx', 'HOST': '127.0.0.1', 'PORT': '3306', } } -
MIDDLEWARE删除’django.middleware.csrf.CsrfViewMiddleware’
前后端分离的项目,引入了jwt,需要将csrf去掉,否则接口都报错403
-
2. 生成token
-
我的接口定义在user子模块,所以,需要先创建user子模块
在PyCharm -> Tools -> Run manage.py Task 中执行命令
# 创建user子模块 startapp user # 迁移数据表 makemigrations migrate -
在user子模块中创建urls.py文件
from django.urls import path from rest_framework_simplejwt.views import ( TokenObtainPairView, TokenRefreshView, TokenVerifyView, ) # rest_framework_simplejwt自带三个视图TokenObtainPairView、TokenVerifyView、TokenRefreshView,用于生成token、验证token、刷新token urlpatterns = [ path('login', TokenObtainPairView.as_view(), name='token_obtain_pair'), path('verify', TokenVerifyView.as_view(), name='token_verify'), path('refresh', TokenRefreshView.as_view(), name='token_refresh'), ] -
在主模块的urls.py文件中引入user子模块
from django.urls import path, include urlpatterns = [ path('user/',include('user.urls')), ] -
调用接口验证,发现并不能生成token


原因:框架使用的是auth_user数据表的用户,对于不存在于auth_user数据表的用户名和密码,调用接口会报上面的错误。
解决方案:在PyCharm -> Tools -> Run manage.py Task 中执行命令,创建用户
createsuperuser
此时在auth_user表中会新增一行用户名为admin的数据,再次调用接口,执行成功。



3. 使用自定义用户模型
如果不想使用auth_user表,想要自定义用户表,则自定义的用户模型需要继承AbstractUser
-
在user/model.py中新增模型,只需添加自定义的字段,username、password、email等字段在AbstractUser中包含。
class SysUser(AbstractUser): avatar = models.CharField(max_length=255, null=True, verbose_name="头像") phone_number = models.CharField(max_length=11, null=True, verbose_name="手机号") status = models.IntegerField(null=True, default=0, verbose_name="帐号状态(0正常,1停用)") remark = models.CharField(max_length=1024, null=True, verbose_name="备注") class Meta: db_table = 'sys_user' -
模型序列化
在user/model.py中新增
from rest_framework import serializers class SysUserSerializer(serializers.ModelSerializer): class Meta: model = SysUser fields = '__all__' -
在settings.py中设置使用自定义用户类进行JWT鉴权 (配置为:app真实名称.自定义模型类名)
AUTH_USER_MODEL = 'user.SysUser' -
执行数据迁移
makemigrations migrate此时数据库中会新建数据表sys_user。
-
自定义注册视图,用于注册用户
在user/views.py中新增RegisterView
@authentication_classes([]) @permission_classes([]) class RegisterView(APIView): def post(self, request): serializer = SysUserSerializer(data=request.data) if serializer.is_valid(): user = SysUser(**serializer.validated_data) # 对密码加密 user.set_password(serializer.validated_data['password']) user.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)在user/urls.py新增path
path('register', RegisterView.as_view(), name='register'),注意:
- @authentication_classes([]) 和 @permission_classes([]) 这两个装饰器用于对某个视图去除jwt鉴权
- 密码一定要加密,否则会鉴权失败
调用接口测试:

-
自定义登录视图,继承TokenObtainPairView
在user/views.py中新增LoginView
class LoginView(TokenObtainPairView): def post(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) try: serializer.is_valid(raise_exception=True) except TokenError as e: raise InvalidToken(e.args[0]) return Response(serializer.validated_data, status=status.HTTP_200_OK)再次调用login接口,生成token成功。
更多推荐
所有评论(0)