simple-jwt快速入门(包含自定制)

simple-jwt快速入门(包含自定制)

目录

  • simple-jwt快速入门(包含自定制)
    • 安装
    • 路由层
    • 视图层
    • 全局配置
    • 前端传入参数
    • 配置文件
    • 定制登录返回格式
    • 定制payload格式
    • 自定制签发-认证

安装

pip install djangorestframework-simplejwt

路由层

from rest_framework_simplejwt.views import TokenObtainPairView

urlpatterns = [
    path('login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
]
  • 浏览器路径随便填,但是必须要调用TokenObtainPairView
  • TokenObtainPairView:登录接口
  • TokenRefreshView:刷新token
  • TokenVerifyView:校验token

视图层

# views.py
from rest_framework.permissions import IsAuthenticated
from rest_framework_simplejwt.authentication import JWTAuthentication

class UserDetail(ModelViewSet):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]
  • 在需要登录才能访问的视图类中加入JWTAuthenticationIsAuthenticated验证

  • 此时相当于用DRF自带的验证视图,他会根据django自带的auth表为我们进行校验,并返回access和refresh

全局配置

REST_FRAMEWORK = {
    # DRF默认权限类
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    # DRF默认认证类
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}

前端传入参数

由于simple-jwt会默认校验auth表中的数据,因此不需要再额外编写视图类,直接传入参数即可(参数要和数据库字段一致)

image-20240419220750941

  • access:校验用的信息,在访问需要登录才能使用的视图方法时需要将它放入浏览器

image-20240419220940947

  • Key:必须填Authorization
  • Value:必须填Bearer+空格+access参数

配置文件

simple-jwt有默认的配置参数

rest_framework_simplejwt—settings.py

DEFAULTS = {
    # Access Token的有效期
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
    # Refresh Token的有效期
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
    # 是否自动刷新Refresh Token
    "ROTATE_REFRESH_TOKENS": False,
    # 刷新Refresh Token时是否将旧Token加入黑名单,如果设置为False,则旧的刷新令牌仍然可以用于获取新的访问令牌
    "BLACKLIST_AFTER_ROTATION": False,
    # 如为True,则在每次使用访问令牌进行身份验证时,更新用户最后登录时间
    "UPDATE_LAST_LOGIN": False,
    # 加密算法
    "ALGORITHM": "HS256",
    # 签名秘钥,这里使用Django的SECRET_KEY
    "SIGNING_KEY": settings.SECRET_KEY,
    # 用于验证jwt签名的秘钥返回的内容
    "VERIFYING_KEY": "",
    # JWT中的"Audience"声明,用于指定该JWT的预期接收者
    "AUDIENCE": None,
    # JWT中的"Issuer"声明,用于指定该JWT的发行者
    "ISSUER": None,
    # 用于序列化JWT负载的JSON编码器。默认为Django的JSON编码器
    "JSON_ENCODER": None,
    # 包含公钥的URL,用于验证JWT签名
    "JWK_URL": None,
    # 允许的时钟偏差量,以秒为单位
    "LEEWAY": 0,
    # 用于指定JWT在HTTP请求头中使用的身份验证方案。默认为"Bearer"
    "AUTH_HEADER_TYPES": ("Bearer",),
    # 包含JWT的HTTP请求头的名称。默认为"HTTP_AUTHORIZATION"
    "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
    # 用户模型中用作用户ID的字段。默认为"id"
    "USER_ID_FIELD": "id",
    # JWT负载中包含用户ID的声明。默认为"user_id"
    "USER_ID_CLAIM": "user_id",
    # 用于指定用户身份验证规则的函数或方法。默认使用Django的默认身份验证方法进行身份验证
    "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",
    # 用于指定可以使用的令牌类。默认为"rest_framework_simplejwt.tokens.AccessToken"
    "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
    # JWT负载中包含令牌类型的声明。默认为"token_type"
    "TOKEN_TYPE_CLAIM": "token_type",
    # JWT负载中包含JWT ID的声明。默认为"jti"
    "JTI_CLAIM": "jti",
    # 用于指定可以使用的用户模型类
    "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",
    # 在使用滑动令牌时,JWT负载中包含刷新令牌过期时间的声明
    "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
    # 滑动令牌的生命周期。默认为5分钟
    "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
    # 滑动令牌可以用于刷新的时间段。默认为1天
    "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),
    # 用于生成access和刷refresh的序列化器
    "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",
    # 用于刷新访问令牌的序列化器
    "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer",
    # 用于验证令牌的序列化器
    "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer",
    # 用于列出或撤销已失效JWT的序列化器
    "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,
    # 在令牌中用于标识撤销令牌的声明
    "REVOKE_TOKEN_CLAIM": "hash_password",
}

定制登录返回格式

  • 自定义一个序列化类,重写validate方法
class CommonTokenObtainSerializer(TokenObtainPairSerializer):
    def validate(self, attrs):
        # 获取父类中的原数据
        dic = super().validate(attrs)
        data = {'code': 100,
                'msg': '登录成功',
                'username': self.user.username,
                'refresh': dic.get('refresh'),
                'access': dic.get('access')
                }
        return data
  • 配置文件注册
# settings.py
SIMPLE_JWT = {
    'TOKEN_OBTAIN_SERIALIZER': 'user.userserializers.CommonTokenObtainSerializer'
}

image-20240419233002835

定制payload格式

class CommonTokenObtainSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        # 获取父类得到的token
        token = super().get_token(user)
        print(token.payload)
        token['name'] = user.username
        return token

    def validate(self, attrs):
        dic = super().validate(attrs)
        data = {'code': 100,
                'msg': '登录成功',
                'username': self.user.username,
                'refresh': dic.get('refresh'),
                'access': dic.get('access')
                }
        return data
  • 获取payload属性得到{'token_type': 'refresh', 'exp': 1713627459, 'iat': 1713541059, 'jti': '8cf1b417155d4ca59965b6625b73831d', 'user_id': 2}
  • 因此可以直接token['name']为payload添加属性
  • 重写后jwt的第三段也会跟着改变

自定制签发-认证

  • 自己生成JWT
  • 用钩子函数将自己要签发的JWT放入序列化类
  • 将签发的JWT放入浏览器再被自定制的认证类接受
  • 校验JWT的合法性然后返回
# views.py
import uuid
from datetime import datetime

from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from user import models
from user.MyAuthentication import JWTOurAuth
from user.MySerializers import UserSerializer
from rest_framework_simplejwt.authentication import JWTAuthentication


class UserView(GenericViewSet):
    queryset = models.UserLog.objects.all()
    serializer_class = UserSerializer
    authentication_classes = [JWTAuthentication]
    permission_classes = []	# 局部禁用权限校验

    @action(methods=['POST'], detail=False)
    def login(self, request):
        username = (request.data.get('username'))
        password = (request.data.get('password'))
        serializer = self.get_serializer(data=request.data)
        
        # 用户密码正确则签发,并发送给浏览器META中,顺带返回JWT
        if models.UserLog.objects.get(username=username).check_password(password):
            if serializer.is_valid():
                request.META['MY_TOKEN'] = serializer.validated_data['JWT']
                return Response({"msg": '登录成功', 'result': serializer.validated_data})
        else:
            return Response({"msg": '账号或密码错误'})


class UserDetail(ModelViewSet):
    queryset = models.UserLog.objects.all()
    serializer_class = UserSerializer
    authentication_classes = [JWTOurAuth]	# 使用自定义的认证类

    @action(methods=['GET'], detail=False)
    def findall(self, request):
        res = self.get_queryset()
        serializer = self.get_serializer(instance=res, many=True)
        return Response({'msg': '查询成功', 'result': serializer.data})

# serializer.py
from datetime import datetime

from rest_framework import serializers
from .MyJWT import MyJWT
from .models import UserLog


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

    def validate(self, attrs):
        # 模拟JWT第二段
        userinfo = {'name': attrs["username"], 'time_field': str(datetime(2024, 1, 1, 12, 0)), 'time_expires': str(
            datetime(2024, 1, 2, 12, 0)), 'level': UserLog.objects.get(username=attrs["username"]).level}
        jwt_obj = MyJWT(payload=userinfo)	# 将用户数据放入自定制的JWT生成类中生成JWT
        JWT = jwt_obj.Issuance()
        attrs['JWT'] = JWT	# 将生成的JWT返回
        return attrs
# MyJWT.py 用于生成JWT格式字符串
from datetime import datetime
import json
import base64
import hashlib


class MyJWT:
    def __init__(self, payload=None, token=None):
        self.header = {'type': 'jwt', 'alg': 'md5'}
        self.payload = payload
        self.token = token

    def get_base64(self, info):
        return base64.b64encode((json.dumps(info)).encode(encoding='utf-8'))

    def get_md5(self, header, payload):
        md5 = hashlib.md5()
        md5.update(header)
        md5.update(payload)
        md5.update(b'7777')  # 盐
        return md5.hexdigest()

    def get_token(self, header, payload):
        base64_header = self.get_base64(header)
        base64_payload = self.get_base64(payload)
        token = f'{base64_header.decode(encoding="utf8")}.{base64_payload.decode(encoding="utf8")}.{self.get_md5(base64_header, base64_payload)}'
        return token

    def check_token(self, token):
        base64_header, base64_payload, sign = token.split('.')
        token = self.get_md5(base64_header.encode('utf8'), base64_payload.encode('utf8'))

        if sign == token:
            return True
        else:
            return False

    def Issuance(self):
        token = self.get_token(self.header, self.payload)
        return token

    def Validate(self, token):
        if self.check_token(token):
            return True
        else:
            return False

    @staticmethod
    def get_user(Token):
        if 'name' not in  json.loads(base64.b64decode(Token.split('.')[1]).decode(encoding='utf8')):
            return False
        return json.loads(base64.b64decode(Token.split('.')[1]).decode(encoding='utf8'))['name']
    
# 使用方法---放入数据(第二段)即可调用Issuance方法获取生成的JWT,调用Validate方法校验参数Token是否与原数据匹配
# userinfo = {'name': '张三', 'age': 18, 'time_field': str(datetime(2024, 1, 1, 12, 0)), 'time_expires': str(
#     datetime(2024, 1, 2, 12, 0)), 'level': 1}
# jwt = MyJWT(payload=userinfo)
# Token = jwt.Issuance()
# user = MyJWT.get_user(Token)
# Token_validate = jwt.Validate(Token)
# MyAuthentication.py
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_simplejwt.authentication import JWTAuthentication

from .MyJWT import MyJWT


class JWTOurAuth(JWTAuthentication):
    def authenticate(self, request):
        # 从浏览器获取token
        if 'HTTP_TOKEN' not in request.META:
            raise AuthenticationFailed("请添加token")
        jwt = request.META['HTTP_TOKEN']
        # 如果验证通过则直接返回用户与jwt字符串
        jwt_obj = MyJWT()
        JWT_validate = jwt_obj.Validate(jwt)
        if JWT_validate:
            return jwt_obj.get_user(jwt), jwt
        raise AuthenticationFailed('你的JWT有误')
      if 'HTTP_TOKEN' not in request.META:
            raise AuthenticationFailed("请添加token")
        jwt = request.META['HTTP_TOKEN']
        # 如果验证通过则直接返回用户与jwt字符串
        jwt_obj = MyJWT()
        JWT_validate = jwt_obj.Validate(jwt)
        if JWT_validate:
            return jwt_obj.get_user(jwt), jwt
        raise AuthenticationFailed('你的JWT有误')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/563078.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【 AIGC 研究最新方向(上)】面向平面、视觉、时尚设计的高可用 AIGC 研究方向总结

目前面向平面、视觉、时尚等设计领域的高可用 AIGC 方向有以下 4 种: 透明图层生成可控生成图像定制化SVG 生成 本篇(上篇)介绍 1、2,而下篇将介绍 3、4。 透明图层生成 LayerDiffuse 代表性论文:Transparent Imag…

Qt基础之四十六:Qt界面中嵌入第三方程序的一点心得

本文主要讲解QWidget和QWindow的区别,以及如何在QWidget中嵌入第三方程序,并完美解决在QWidget中嵌入某些程序(比如Qt程序)时出现的白边问题。 下面是嵌入QQ音乐的样子,这首歌还不错。 先用spy++查看QQ音乐的窗口信息,如果安装了Visual Studio,工具菜单里自带spy++ 然后…

Spring Boot | Spring Boot 默认 “缓存管理“ 、Spring Boot “缓存注解“ 介绍

目录: 一、Spring Boot 默认 "缓存" 管理 :1.1 基础环境搭建① 准备数据② 创建项目③ 编写 "数据库表" 对应的 "实体类"④ 编写 "操作数据库" 的 Repository接口文件⑤ 编写 "业务操作列" Service文件⑥ 编写 "applic…

Redis入门到通关之数据结构解析-QuickList

文章目录 ☃️前提概要☃️ 配置项相关☃️简要源码☃️总结 Redis中的 QuickList 是一种特殊的数据结构,用于存储列表类型的数据。它的设计目的是在内存中高效地存储和操作大量的列表元素,尤其是当列表长度很大时。 QuickList的内部结构是一个由多个节…

政安晨:【Keras机器学习示例演绎】(八)—— 利用 PointNet 进行点云分割

目录 简介 导入 下载数据集 加载数据集 构建数据集 预处理 创建 TensorFlow 数据集 PointNet 模型 排列不变性 变换不变性 点之间的相互作用 实例化模型 训练 直观了解培训情况 推论 最后说明 政安晨的个人主页:政安晨 欢迎 👍点赞✍评论…

【PCL】教程 implicit_shape_model.cpp 3D点云数据的对象识别 利用隐式形状模型进行训练和识别...

ism_test_cat.pcd 参数:ism_train_cat.pcd 0 ism_train_horse.pcd 1 ism_train_lioness.pcd 2 ism_train_michael.pcd 3 ism_train_wolf.pcd 4 ism_test_cat.pcd 0 这里红点表示对应感兴趣类别的对象预测中心 ./ism_t…

字节FE:JavaScript学习路线图

JavaScript简介 JavaScript是一种高级的、解释执行的编程语言。它是互联网的三大核心技术之一,与HTML和CSS一同工作,用于创建交互式的网页。JavaScript被所有现代网页浏览器支持而不需要任何插件。它可以增强用户界面和网页的交互性,可以进行…

【讲解下Spring Boot单元测试】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…

FineBi中创建自定义的图表

FineBi中增加自己的自定义图表组件,比如: 的相关笔记: 1 获取有哪些BI自定义图表组件:http://localhost:8080/webroot/decision/v5/plugin/custom/component/list?_=1713667435473[{"name": "图表DEMO_EK","chartType": "amap_demo&q…

GO环境及入门案例

文章目录 简介一、win GO开发环境安装二、Linux go运行环境二、GO代码入门2.1 导包案例2.2 赋值2.3 变量、函数2.4 三方库使用 简介 go不是面向对象语言, 其指针、结构体等比较像C,知名的go 开源项目有docker k8s prometheus node-exporter等 一、win …

如何在3dMax中快速打包mzp 文件?

如何在3dMax中创建mzp 文件? 我喜欢将我的Maxscript脚本发布为mzp文件。这是一个为3dMax构建的自解压zip文件。在mzp文件中,您可以捆绑Maxscript脚本文件、图片、预设或其他文件,并链接安装时执行的特殊操作。 在3dMax中使用大型脚本时&…

耐高温300度锅炉轴承,江苏鲁岳轴承制造的行业标杆

自润滑轴承-产品类型-耐高温轴承-不锈钢轴承-江苏鲁岳轴承制造有限公司。锅炉轴承,耐高温至200度-800度。 江苏鲁岳轴承制造有限公司,一家专注于锅炉轴承和耐高温轴承的研发与生产的企业,致力于为客户提供高质量、高性能的轴承解决方案。其中…

LeetCode题练习与总结:矩阵置零--73

一、题目描述 给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1: 输入:matrix [[1,1,1],[1,0,1],[1,1,1]] 输出:[[1,0,1],[0,0,0],[1,0,1]]示例 2&#xf…

Linux-内存文件

1. 基础IO操作 1.1 c语言的IO接口 fopen:打开一个文件,按照指定方式 参数:filename 文件名,也可以是路径,mode:打开方式 返回打开的文件指针 fread:从指定流中读数据 参数:从FIL…

Selenium web自动化测试环境搭建

Selenium web自动化环境搭建主要要经历以下几个步骤: 1、安装python 在python官网:Welcome to Python.org,根据各自对应平台如:windows,下载相应的python版本。 ​ 下载成功后,点击安装包,一直…

解释一下“暂存区”的概念,在Git中它扮演什么角色?

文章目录 暂存区在Git中的概念与作用什么是暂存区(Staging Area)暂存区的位置和结构 暂存区在Git工作流程中的角色1. 分离工作区与版本库的交互示例代码与操作步骤示例1:将工作区的修改添加至暂存区 2. 控制提交内容的粒度示例2:分…

【Linux】虚拟机与Xshell及VS Code的连接

一、基础环境 虚拟机:VMware Workstation Pro 虚拟机镜像:ubuntu-18.04.5-desktop-amd64.iso 其他:Xshell 6、Xftp 6、Visual Studio Code 上述软件的安装操作不再赘述,CSDN上有大量的优秀博文,可参考:详细…

安装和部署maven

准备工作 maven下载地址:https://maven.apache.org/download.cgi 使用wget将maven包下载到linux环境上,/toos/ 目录下(也可用迅雷) wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.g…

小游戏贪吃蛇的实现之C语言版

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏:C语言 目录 游戏前期准备: 设置控制台相关的信息 GetStdHandle GetConsoleCursorInfo SetConsoleCursorInfo SetConsoleCu…

VSCode插件开发学习

一、环境准备 0、参考文档:VS Code插件创作中文开发文档 1、大于18版本的nodejs 2、安装Yeoman和VS Code Extension Generator: npm install -g yo generator-code 3、生成脚手架 yo code 选择内容: ? What type of extension do yo…