DRF JWT认证进阶

这篇具有很好参考价值的文章主要介绍了DRF JWT认证进阶。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

JWT认证进阶

【0】准备工作

(1)模型准备

  • 模型准备(继承djangoauth_user表)
from django.db import models
from django.contrib.auth.models import AbstractUser

class UserInfo(AbstractUser):
    mobile = models.CharField(max_length=11, verbose_name='手机号码')

  • 添加配置文件,修改用户模型表为自定义表
AUTH_USER_MODEL = 'app名称.UserInfo'

(2)知识点绑定方法

  • 详情请见:Python 面向对象之绑定和非绑定方法_python 绑定方法-CSDN博客
  • 实例方法
    • 对象调用实例方法时(对象.实例方法()),自动将对象当作第一个参数传入
    • 类调用实例方法时(类.实例方法(类())),需要手动传入一个实例
  • 类方法
    • 类调用类方法时(类.类方法()),自动将类当作第一个参数传入
    • 对象调用类方法时(对象.类方法()),自动将对象的类当作第一个参数传入
  • 简单示例
class A:
    def __init__(self, name):
        self.name = name

    @classmethod
    def hi(cls):
        print(f"{cls.__name__} say hi")

    def hello(self):
        print(f"{self.name} say hello")


a = A('bruce')
# 实例调用类方法,自定将类传入
a.hi()
# 类调用实例方法,需要手动将实例对象传入
A.hello(a)

(3)保存信息显示中文

  • 在配置文件中注册app就可以
INSTALLED_APPS = [
    'rest_framework_simplejwt',
]

【1】jwt配置文件

(1)整体查看

  • 这些内容都在from rest_framework_simplejwt import settings可以自己去查看
DEFAULTS = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),# 访问令牌的有效期。这里设置为5分钟。
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),# 刷新令牌的有效期。这里设置为1天。
    "ROTATE_REFRESH_TOKENS": False,# 是否每次使用刷新令牌时都生成新的刷新令牌。这里设置为False。
    "BLACKLIST_AFTER_ROTATION": False,# 刷新令牌在旋转后是否应该被加入黑名单。这里设置为False。
    "UPDATE_LAST_LOGIN": False,# 是否在每次验证令牌时更新用户的最后登录时间。这里设置为False。
    "ALGORITHM": "HS256",# 用于签名的算法。这里使用的是HS256。
    "SIGNING_KEY": settings.SECRET_KEY,# 用于签名的密钥。这里使用的是Django的SECRET_KEY。
    "VERIFYING_KEY": "",# 用于验证令牌的密钥。这里没有设置。
    "AUDIENCE": None,# JWT的接收者。这里没有设置。
    "ISSUER": None,# JWT的签发者。这里没有设置。
    "JSON_ENCODER": None,# 用于序列化JWT负载的JSON编码器。这里没有设置。
    "JWK_URL": None,# JSON Web Key Set的URL,用于公钥检索。这里没有设置。
    "LEEWAY": 0,# 在验证JWT的时间戳时允许的时间误差(秒)。这里设置为0。
    "AUTH_HEADER_TYPES": ("Bearer",),# 认证头中可以接受的令牌类型。这里设置为只接受"Bearer"类型。
    "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",# 认证头的名称。这里设置
    "USER_ID_FIELD": "id",# 用户的ID字段名。这里设置为"id"。
    "USER_ID_CLAIM": "user_id",# JWT中用户ID的声明名称。这里设置为"user_id"。
    "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",# 用于验证用户的规则。这里使用的是默认规则。
    "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),# l令牌类。这里设置为只使用访问令牌。
    "TOKEN_TYPE_CLAIM": "token_type",# 用于表示用户的模型类。这里使用的是默认模型。
    "JTI_CLAIM": "jti",#  JWT的JTI(JWT ID)声明名称。这里设置为"jti"。
    "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",# 用于表示用户的模型类。这里使用的是默认模型。
    "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",# 滑动刷新令牌中的过期声明名称。这里设置为"refresh_exp"。
    "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),# 滑动访问令牌的有效期。这里设置为5分钟。
    "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),# 滑动刷新令牌的有效期。这里设置为1天。
    "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",# 用于获取令牌的序列化器。这里使用默认的序列化器。
    "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer",# 用于刷新令牌的序列化器。这里使用默认的序列化器。
    "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer",# 用于验证令牌的序列化器。这里使用默认的序列化器。
    "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer",# 用于黑名单令牌的序列化器。这里使用默认的序列化器。
    "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer",# 用于获取滑动令牌的序列化器。这里使用默认的序列化器。
    "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer",# 用于刷新滑动令牌的序列化器。这里使用默认的序列化器。
    "CHECK_REVOKE_TOKEN": False,# 是否检查令牌是否已被撤销。这里设置为False。
    "REVOKE_TOKEN_CLAIM": "hash_password",# 用于撤销令牌的声明名称。这里设置为"hash_password"。
}

(2)常用的配置

  • ACCESS_TOKEN_LIFETIME: 访问令牌的有效期。这里设置为5分钟。

  • REFRESH_TOKEN_LIFETIME: 刷新令牌的有效期。这里设置为1天。

  • TOKEN_OBTAIN_SERIALIZER:可自定义登录的序列化器

【2】定制登录返回格式

(1)定制整体返回格式

  • jwt默认返回格式是一个字典,包含两个键值对
    • 一个是刷新相关的token,另一个是登录相关的token
  • 我们期望的格式是一个大字典,包含返回自定义状态码code、描述信息msg、用户名username和默认的两个token
    • 所以需要我们自定义,这里的方法是替换默认的登录序列化类,自定义序列化类以实现自定义的返回整体格式
  • 通过默认配置:
    • "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer"
    • 可知道这个类是负责登录序列化的,为了方便,继承它,重写它的方法,添加自定义的属性
    • 通过简单观察源码发现,返回的内容就是validate里面的data,所以只需要在这个data中添加修改一下字段就可以

DRF JWT认证进阶,Django RESTFrameWork,sqlite,数据库,python,django

  • 代码
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class JWTTokenPairSerializer(TokenObtainPairSerializer):
    def validate(self, attrs):
        data = super().validate(attrs)
        new_data = {
            "code": 100,
            "msg": '登录验证成功',
            "username": self.user.username,
            "refresh": data.get("refresh"),
            "access": data.get("access"),
        }
        return new_data
# 配置文件替换默认的序列化类
SIMPLE_JWT ={
    'TOKEN_OBTAIN_SERIALIZER':'自定义序列化类的位置.JWTTokenPairSerializer'
}

# 使用默认的JWT登录
from django.urls import path
from rest_framework_simplejwt.views import token_obtain_pair
urlpatterns = [
    path('v0/login/', token_obtain_pair),
]

DRF JWT认证进阶,Django RESTFrameWork,sqlite,数据库,python,django

(2)定制payload载荷

  • 默认载荷部分包含了

    • token_type表示这是一个访问令牌(access token)
    • exp是令牌的过期时间(UNIX时间戳)
    • iat是令牌的签发时间
    • jti是令牌的唯一标识符
    • user_id是用户ID
  • 现在思考如何添加自定义字段,比如用户的用户名

    • 还是通过一步一步的找token,最终找到了载荷payload,是一个字典所以可以尝试,像普通字典一样添加新的信息
    • 注意:这里面虽然有类方法,但是无论是self还是super都是实例对象,可以直接调用类方法

DRF JWT认证进阶,Django RESTFrameWork,sqlite,数据库,python,django

  • 代码:还是修改序列化类
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class JWTTokenPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['username'] = user.username
        return token
  • 检查,添加成功
import base64

s = 'token第二段==='
res = base64.b64decode(s.encode('utf8'))
# b'{"token_type":"access","exp":1713528635,"iat":1713528335,"jti":"cc57595cd70f4938baa4673a6f1538ad","user_id":1}
# b'{"token_type":"access","exp":1713530348,"iat":1713530048,"jti":"6807d0722efb41bba01742a44767c18d","user_id":1,"username":"admin"}'

【3】多方式登录

(1)简介

  • 实际的案例中,登录的方式有很多种,既可以是用户名,还可以是手机号,还可以是邮箱等,并且他们的登录输入入口都是一个,所以这里将实现这种接口

DRF JWT认证进阶,Django RESTFrameWork,sqlite,数据库,python,django

(2)登录视图函数和路由

  • 序列化类有检验功能,所以重心不在这里
# 路由层
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from .views import JWTLoginAPIView

router = SimpleRouter()
router.register('', JWTLoginAPIView, basename='login')
urlpatterns = [
    path('v1/', include(router.urls)),
]
# 视图层
from rest_framework.viewsets import GenericViewSet
from .serializer import JWTTokenSerializer
from rest_framework.response import Response
from rest_framework.decorators import action


class JWTLoginAPIView(GenericViewSet):
    serializer_class = JWTTokenSerializer

    @action(methods=['post'], detail=False)
    def login(self, request, *args, **kwargs):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            refresh = ser.context.get('refresh')
            access = ser.context.get('access')
            return Response({"code": 100, "msg": "登录验证成功", "refresh": refresh, "access": access})
        return Response({"code": 100, "msg": ser.erros})

(3)序列化类

  • 序列化类的检验分为三个过程,首先是字段参数(包括validators),然后是局部钩子,最后是全局钩子
  • 由于需要校验用户输入字段和密码字段,所以使用全局钩子
  • 整体逻辑
    • 使用不同方法区分传入的值是电话,还是邮箱,还是手机号
    • 由于使用的是django的用户表,所以要用相应的加密方法判断密码
    • 在定制载荷payload中,知道了RefreshToken处理token,所以要调用这个类的类方法for_user处理
import re

from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework_simplejwt.tokens import RefreshToken
from .models import UserInfo


class JWTTokenSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField()

    def validate(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        if re.match(r'^1[3-9][0-9]{9}$', username):
            user = UserInfo.objects.filter(username=username).first()
        elif re.match(r"/^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/", username):
            user = UserInfo.objects.filter(username=username).first()
        else:
            user = UserInfo.objects.filter(username=username).first()
        # 使用的是django的表,需要使用响应的方法进行密码检验
        if user and user.check_password(password):
            # 获取token
            token = RefreshToken.for_user(user)
            self.context['refresh'] = str(token)
            self.context['access'] = str(token.access_token)
            return attrs
        raise ValidationError("用户名或者密码错误")

DRF JWT认证进阶,Django RESTFrameWork,sqlite,数据库,python,django

【4】自定义用户表、手动签发和认证

(1)模型表

  • 用户表用普通的表
  • 创建一个数据表用于侧式认证功能
from django.db import models

class UserNormal(models.Model):
    username = models.CharField(max_length=64, verbose_name='用户名')
    password = models.CharField(max_length=64, verbose_name='密码')

class Book(models.Model):
    name = models.CharField(max_length=64, verbose_name="书名")
    price = models.CharField(max_length=64, verbose_name="价格")
    publish = models.CharField(max_length=64, verbose_name="出版社")

(2)路由层

  • 自动路由
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from .views import JWTLoginAPIView, BookAPIView

router = SimpleRouter()
router.register('', JWTLoginAPIView, basename='login')
router.register('book', BookAPIView, basename='book')
urlpatterns = [
    path('v1/', include(router.urls)),
]

(3)视图层

  • 和之前没有区别,多创一个视图类用于测试
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from .serializer import JWTTokenSerializer, BookModelSerializer
from rest_framework.response import Response
from rest_framework.decorators import action
from .models import Book
from .authentication import JWTAuth

class BookAPIView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer
    authentication_classes = [JWTAuth]
    
class JWTLoginAPIView(GenericViewSet):
    serializer_class = JWTTokenSerializer

    @action(methods=['post'], detail=False)
    def login(self, request):
        ser = self.get_serializer(data=request.data)
        if ser.is_valid():
            refresh = ser.context.get('refresh')
            access = ser.context.get('access')
            return Response({"code": 100, "msg": "登录验证成功", "refresh": refresh, "access": access})
        return Response({"code": 100, "msg": ser.errors})

(4)序列化

import re

from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework_simplejwt.tokens import RefreshToken
from .models import UserInfo, Book, UserNormal


class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = "__all__"


class JWTTokenSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField()

    def validate(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        user = UserNormal.objects.filter(username=username, password=password).first()
        if user:
            # 获取token
            token = RefreshToken.for_user(user)
            self.context['access'] = str(token.access_token)
            self.context['refresh'] = str(token)

            return attrs
        raise ValidationError("用户名或者密码错误")

(5)认证类

from rest_framework_simplejwt.authentication import JWTAuthentication
from .models import UserNormal
from rest_framework.exceptions import AuthenticationFailed


class JWTAuth(JWTAuthentication):
    def authenticate(self, request):
        token = request.META.get("HTTP_AUTHORIZATION")

        if token:
            # 调用父类的方法验证token,内部会自动验证抛出异常
            validated_token = super().get_validated_token(token)
            # 放入的默认信息是user_id
            user_id = validated_token.get('user_id')
            user = UserNormal.objects.filter(pk=user_id)
            return user, token
        else:
            raise AuthenticationFailed("登录认证信息认证失败")

(6)测试

  • 注意:上面调用的方法,不可以在token的前面带任何参数

DRF JWT认证进阶,Django RESTFrameWork,sqlite,数据库,python,django

  • 解决办法:
    • 使用父类的获取原生token方法,这样仍将携带配置文件中的要求(Bearer,也可以自定义其他的)
header = self.get_header(request)
token = self.get_raw_token(header)

DRF JWT认证进阶,Django RESTFrameWork,sqlite,数据库,python,django文章来源地址https://www.toymoban.com/news/detail-859764.html

到了这里,关于DRF JWT认证进阶的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Django进阶:DRF(Django REST framework)

    DRF 即 Django REST framework 的缩写,官网上说: Django REST framework 是一个强大而灵活的工具包,用于 构建Web API 。 简单来说:通过DRF创建API后,就可以通过HTTP请求来获取、创建、更新或删除数据(CRUD)。 那么为什么要构建API呢? 在Django中,我们通过 model-view-template 实现了 后端和前

    2024年02月11日
    浏览(41)
  • Django REST Framework完整教程-认证与权限-JWT的使用

    阅读本文之前,请读者先阅读: https://plugin.blog.csdn.net/article/details/133853377,如果已经知晓Django REST Framework的基础,可以继续阅读本文内容。 认证(Authentication)与权限(Permission)不是一回事。认证是通过用户提供的用户ID/密码组合或者Token来验证用户的身份。权限(Permission)的校验

    2024年02月07日
    浏览(41)
  • django如何连接sqlite数据库?

    目录 一、SQLite数据库简介 二、Django连接SQLite数据库 1、配置数据库 2、创建数据库表 三、使用Django ORM操作SQLite数据库 1、定义模型 2、创建对象 3、查询对象 总结 本文将深入探讨如何在Django框架中连接和使用SQLite数据库。我们将介绍SQLite数据库的特点,Django的数据库配置,以

    2024年02月06日
    浏览(55)
  • Android 进阶 1、sqlite数据库

    在我们学会了Android的基本使用之后就需要往高处发展了,毕竟水往高处流,很多时候我们学习一门技术感觉没有收获都是因为还没到那个层次,当你一步步往上走的时候就会渐渐发现自己收获的越来越多,进步也就会越来越快了,废话不多说,回到正题; 1、认识数据库 安卓

    2024年02月10日
    浏览(48)
  • 【Django】让SQLite数据库中表名支持重命名的方法

    修改了数据库表名之后,更新数据库时跳错: 意思就是 SQLite 数据库不支持重命名的操作,添加atomic = False即可: Migration 在 py36Libsite-packagesdjangodbmigrationsmigration.py 的位置 将 atomic = True 改成 atomic = False

    2024年02月10日
    浏览(52)
  • drf——jwt

    2024年02月06日
    浏览(41)
  • 基于Qt数据库项目实现(Sqlite3为例)|考查数据库、表格(QTableView 显示)(进阶)

    01 数据库表格(QTableView 显示) 本小节设计一个生活中的例子,使用数据库修改/查询员工的编号、姓名、年龄、性别与照片信息。 本例将数据库的内容显示到 QTableView 上。如果只是简单的显示数据库的内容到QTableView 上,可以使用下面的方法,此方法 QTableView 上可以看到

    2024年02月20日
    浏览(50)
  • 基于Qt数据库项目实现(Sqlite3为例)|考查数据库、绘制(画家)、事件等知识点(进阶)

    坚持最初的梦想,扬帆起航,乘风破浪,永不言败。 01 数据库 数据库是什么?简易言之,就是保存数据的文件。可以存储大量数据,包括插入数据、更新数据、截取数据等。用专业术语来说,数据库是“按照数据结构来组织、存储和管理数据的仓库”。是一个长期存储在计

    2024年02月19日
    浏览(47)
  • Django创建应用、ORM的进阶使用及模型类数据库迁移

    Django 项目就是基于 Django 框架开发的 Web 应用,它包含了一组配置和多个应用,我们把应用称之为 App,在前文中对它也做了相应的介绍,比如 auth、admin,它们都属于 APP。 一个 App 就是一个 Python 包,通常一个 App 可以包含模型、视图、模板和 URL 配置文件,可以被应用到多个

    2024年02月09日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包