@[TOC]rest_framework_simplejwt自定义使用——登录功能
Django中的rest_framework_simplejwt
jwt的概念这里就不解释了
一、使用默认的rest_framework_simplejwt实现登录功能
1.1 创建django空项目
#创建django项目
django-admin startproject login
# 进入login目录
cd login
#创建app
django-admin startapp user
#初始化数据库,默认使用SQLit3
python manage.py makemigrations
#创建表结构
python manage.py migrate
# 创建超级用户账号,用户名:root,密码:root,邮箱:root@qq.com
python manage.py createsuperuser
# 安装rest_framework和rest_framework_simplejwt
pip install rest_framework
pip install rest_framework_simplejwt
1.2 初始化项目
主要修改setting.py文件和login目录下的urls.py文件:
setting.py
INSTALLED_APPS = [
...
'user.apps.UserConfig', # 新增
'rest_framework', # 新增
'rest_framework_simplejwt' # 新增
]
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
# 设置全局权限模式,用户认证通过可访问
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': [
# 使用默认的认证类的认证方式
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
}
from datetime import timedelta
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=100), # 访问令牌的有效时间
"REFRESH_TOKEN_LIFETIME": timedelta(days=1), # 刷新令牌的有效时间
"ROTATE_REFRESH_TOKENS": False, # 若为True,则刷新后新的refresh_token有更新的有效时间
"BLACKLIST_AFTER_ROTATION": True, # 若为True,刷新后的token将添加到黑名单中,
"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",
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",), # default: access
"TOKEN_TYPE_CLAIM": "token_type", # 用于存储令牌唯一标识符的声明名称 value:"access","sliding","refresh"
"JTI_CLAIM": "jti",
"SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp", # 滑动令牌是既包含到期声明又包含刷新到期声明的令牌
"SLIDING_TOKEN_LIFETIME": timedelta(minutes=5), # 只要滑动令牌的到期声明中的时间戳未通过,就可以用来证明身份验证
"SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1), # path("token|refresh", TokenObtainSlidingView.as_view())
}
urls.py
from django.urls import path
from rest_framework_simplejwt.views import TokenRefreshView, TokenVerifyView, TokenObtainPairView
urlpatterns = [
path("login/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path("verify/", TokenVerifyView.as_view(), name="token_verify"),
]
这三个接口分别是登录、获取新的token、验证token是否有效
TokenObtainPairView.as_view(),这个接口登录成功后会返回:访问令牌和有效令牌。
1.3 通过postman调用接口验证功能
#启动项目
python manage.py runserver 127.0.0.1:8000
二、自定义JWT认证类和自定义认证登录
2.1 自定义类配置
系统默认的JWT认证使用的默认用户进行验证了,有时候需要我们自定义设置用户表并验证。
创建用户表模型:
user(app)下面models.py:
from django.db import models
from django.contrib.auth.hashers import make_password, check_password
class User(models.Model):
username = models.CharField(max_length=255, unique=True, verbose_name="手机号")
password = models.CharField(max_length=255, unique=False, verbose_name="密码")
is_vip = models.BooleanField(default=False,verbose_name="是否为vip")
vip_expires_at = models.DateTimeField(auto_now_add=True,verbose_name="vip过期时间")
is_active = models.BooleanField(default=True)
def is_authenticated(self):
return True
def set_password(self, raw_password):
self.password = make_password(raw_password)
def check_password(self, raw_password):
return check_password(raw_password, self.password)
class Meta:
db_table = "user"
verbose_name = "用户账号表"
verbose_name_plural = verbose_name
数据迁移,数据库中生成表
#初始化数据库,默认使用SQLit3
python manage.py makemigrations
#创建表结构
python manage.py migrate
在user(app)下创建文件夹utils,并在utils文件夹下创建两个文件,Authentication.py和jwt.py
配置如下,声明一个类MyTokenObtainPairSerializer并继承TokenObtainPairSerializer类,重写validate方法,编写自定义登录认证
Authentication.py
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework import serializers
from user.models import User
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
"""
自定义登录认证,使用自有用户表
username、password这两个字段为必传字段因为 DRF 要检查这些字段是否有效
username_field = 'phone_number' 这是重命名了,username必传字段设置为了phone_number字段必传
phone_number = serializers.CharField(required=False) # 这个是设置了自定义的字段是否必传
"""
def validate(self, attrs):
# self.context['request'].data 中包含了所有前端出过来的参数
username = attrs.get("username")
password = attrs.get("password")
if not username or not password:
raise serializers.ValidationError("phone_number and password are required")
try:
user = User.objects.get(username=username, password=password)
except User.DoesNotExist:
raise serializers.ValidationError("No user found with this username and password.")
print(user)
refresh = self.get_token(user)
data = {"userId": user.id, "token": str(refresh.access_token), "refresh": str(refresh),
'is_vip': user.is_vip}
return data
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
jwt.py
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.exceptions import InvalidToken, AuthenticationFailed
from django.utils.translation import gettext_lazy as _
# 自定义的用户模型
from user.models import User
class MyJWTAuthentication(JWTAuthentication):
'''
修改JWT认证类,返回自定义User表对象
'''
def get_user(self, validated_token):
try:
user_id = validated_token['user_id']
except KeyError:
raise InvalidToken(_('Token contained no recognizable user identification'))
try:
user = User.objects.get(**{'id': user_id})
except User.DoesNotExist:
raise AuthenticationFailed(_('User not found'), code='user_not_found')
return user
setting.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'user.utils.jwt.MyJWTAuthentication' # 认证方式为自定义的认证类
],
}
user(app)下面的views.py文件中,创建一个接口,返回用户的基本信息,用于验证是否自定义认证成功。
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
class TestView(APIView):
def post(self, request, *args, **kwargs):
s = str(request.user.__dict__)
return Response(data=s)
路由设置
urls.py
from django.urls import path
from rest_framework_simplejwt.views import TokenRefreshView, TokenVerifyView
from user.utils.Authentication import MyTokenObtainPairView
from user.views import TestView
urlpatterns = [
path('login/', MyTokenObtainPairView.as_view()),
path("refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path("verify/", TokenVerifyView.as_view(), name="token_verify"),
path("test/", TestView.as_view(), name="token_refresh"),
]
2.2 验证接口功能是否正常
2.2.1 在sqlit3 上面手动创建几个用户,因为没有写注册接口
2.2.2 在postman上验证登录接口, 自定义返回数据,我这里多添加了is_vip字段。
2.2.3 postman上验证刷新token接口
2.2.4 postman上验证登录后的接口,我这里使用的test/路由下的一个接口,用户验证通过了返回用户的所有信息
前端打算使用vue3写一个登录功能的,待更新。。。。