rest_framework_simplejwt自定义使用——登录功能

@[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.pyjwt.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写一个登录功能的,待更新。。。。

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值