DRF JWT认证基础

JWT认证

【1】base64使用

(1)使用场景

  1. 电子邮件附件:由于电子邮件协议只支持 ASCII 字符集,因此,如果要发送非 ASCII 数据(如图片、音频、视频等),需要先将这些数据进行 base64 编码,然后再作为邮件内容发送。
  2. 网页中的嵌入资源:有时为了简化网页资源加载(如图片、CSS、JavaScript 等),可以将其内容使用 base64 编码,然后直接嵌入到 HTML 代码中,从而避免额外的 HTTP 请求。
  3. 配置信息:在某些情况下,配置信息(如 API 密钥、密码等)需要以明文形式存储在配置文件中,但又不想直接暴露明文。此时,可以使用 base64 进行编码。

(2)方法介绍

  • 编码base64.b64encode(s)
    • s:要编码的字节串(bytes)。
      • 类型需要是bytesstr不行
    • 返回:编码后的字节串
  • 解码base64.b64decode(s)
    • s:要解码的 base64 编码的字节串。
      • 长度如果不是4的倍数,后面补等号
    • 返回:解码后的原始字节串

(3)使用示例

  • jsonbase64搭配使用
import base64
import jsoninfo_dict = {'name': "bruce", "age": 18}
info_str = json.dumps(info_dict).encode('utf8')
info_bytes = info_str# 编码
base_data_en = base64.b64encode(info_bytes)
print(base_data_en)  # b'eyJuYW1lIjogImJydWNlIiwgImFnZSI6IDE4fQ=='# 解码
base_data_de = base64.b64decode(base_data_en)
print(base_data_de)  # b'{"name": "bruce", "age": 18}'
  • 图片和base64
import base64# 原始数据URI字符串
picture_data_base64 = ''
# 分割字符串以获取base64编码部分
base64_encoded_data = picture_data_base64.split(',')[-1]# 解码base64数据
picture_bytes = base64.b64decode(base64_encoded_data)# 将解码后的数据写入文件
with open('1.png', 'wb') as f:f.write(picture_bytes)

【2】JWT原理

(1)回顾cookie和session

  • 补充:浏览器根据域名是否相同判断发送指定的cookie信息

    • 浏览器在根据域名判断是否发送cookie时,遵循的是同源策略(Same-origin policy)。
    • 同源策略是浏览器的一种安全策略,它限制了从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。
    • 这里的“源”指的是协议、域名和端口三者的组合
  • cookie

    • 首先浏览器携带用户信息发送给后端,后端进行数据判断以后,执行方法set_cookie,构造一个字典发送给浏览器
    • 浏览器将cookie保存在浏览器中,并且还是明文保存
    • 在之后需要登录认证的操作中,携带cookie进行验证登录

image-20240418185619745

  • session
    • 这里只说不同点,保存的数据是加密的,键值是随机字符串,数据保存在数据库中,信息都是密文

image-20240418191545579

(2)JWT原理

image-20240419144838690

  • JWT(JSON Web Token)的原理基于一种身份认证方案,它使用密钥对数据进行加密和解密,根据两次数据是否一致,判断信息有没有被串改,是签发的数据就可以登录。

    • 加密过程将原始数据(即载荷)和密钥一起进行哈希运算,生成加密后的数据。
    • 解密过程则使用相同的密钥和加密后的数据进行哈希运算,还原出原始数据。
  • JWT主要由三部分构成:头部(Header)、载荷(Payload)和签名(Signature),由.符号分隔。

    1. Header:第一部分是声明类型,例如JWT;第二部分是声明所使用的算法,例如HMAC SHA256RSA等。
    2. Payload:它包含了具体的用户信息,如用户ID、用户名、角色等,也可以包含自定义的其他信息。
    3. Signature:它使用Header和Payload中的数据以及一个密钥来生成签名。签名的作用是确保数据在传输过程中没有被篡改,并且可以由接收方验证发送方的身份。
  • 特点:

    • 数据没有保存在数据库中,对大型项目很有用

【3】simple-jwt简单使用

(1)安装

pip install djangorestframework-simplejwt

(2)使用

  • 注册路由:

    • 首先导包from rest_framework_simplejwt.views import token_obtain_pair

    • 然后编写路由:路由可以自定义,视图函数使用token_obtain_pair

    • from rest_framework_simplejwt.views import token_obtain_pair
      from django.urls import path
      urlpatterns = [path('user/', token_obtain_pair),
      ]
      
  • 指定需要登录的视图函数添加需要认证方法

    • 导包from rest_framework_simplejwt.authentication import JWTAuthentication
    • 导包from rest_framework.permissions import IsAuthenticated
    • 添加到视图中
      • permission_classes = [IsAuthenticated]
      • authentication_classes = [JWTAuthentication]
  • 注册一个用户(需要使用django的user表

    • 创建一个超级用户admin
  • 未登录测试

    • image-20240418195018884
  • 登录测试

    • 首先登录获取access

    • image-20240418195229380

    • headers携带信息进行验证

    • image-20240418195429284

(3)base64解码数据

  • 头部
    • 解码后的结果是{"alg":"HS256","typ":"JWT"},这是JWT的头部,指定了用于签名JWT的算法(在这个例子中是HS256)以及令牌的类型(JWT)。
  • 载荷
    • 这个载荷部分包含了关于这个JWT的一些声明信息,比如token_type表示这是一个访问令牌(access token),exp是令牌的过期时间(UNIX时间戳),iat是令牌的签发时间,jti是令牌的唯一标识符,而user_id是用户ID。
  • 签名:这不是能直接看懂的信息
import base64info_str = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzEzNDQxMjE2LCJpYXQiOjE3MTM0NDA5MTYsImp0aSI6IjU3Y2YxMmNiNjA0OTQxNTU4ODY3ZDAzNGMyZmJmYzQ4IiwidXNlcl9pZCI6Mn0.aT07kjJtvQfRLvt8O6VPTvqIPChc35CLt_aLUUXZYPY'
info_one, info_two, info_three = info_str.split('.')
print(base64.b64decode(info_one.encode('utf8')))
# b'{"alg":"HS256","typ":"JWT"}'
print(base64.b64decode((info_two + '===').encode('utf8')))
# b'{"token_type":"access","exp":1713441216,"iat":1713440916,"jti":"57cf12cb604941558867d034c2fbfc48","user_id":2}'
print(base64.b64decode((info_three + '===').encode('utf8')))
# b'i=;\x922m\xbd\x07\xd1.\xfb|;\xa5ON\xfa\x88<(\\\xdf\x90\x8b\xb5\xa2\xd4QvX='

【4】练习:自定义jwt

(1)基础准备

  • 模型表:自定义一个普通的user
from django.db import models
class User(models.Model):username = models.CharField(max_length=64, verbose_name='用户名')password = models.CharField(max_length=64, verbose_name='密码')
  • 路由层
    • user路由的视图类后续编写,books路由用于检验自定义jwt
from django.urls import path, include
from .views import BookAPIView
from rest_framework.routers import SimpleRouter
from .views import LoginJWTrouter.register(prefix='books', viewset=BookAPIView, basename='books')
urlpatterns = [path('', include(router.urls)),path('user/', LoginJWT.as_view()),
]
  • 书籍相关(检测自定义jwt)
    • JwtAuth是自定义的jwt认证类
# 序列化
from rest_framework.serializers import ModelSerializer
from .models import Book
class BookModelSerializer(ModelSerializer):class Meta:model = Bookfields = '__all__'
# 视图层
from rest_framework.viewsets import ReadOnlyModelViewSet
from .serializer import BookModelSerializer
from .models import Book
from .authentication import JwtAuth
class BookAPIView(ReadOnlyModelViewSet):queryset = Book.objects.all()serializer_class = BookModelSerializerpagination_class = CommonPaginationauthentication_classes = [JwtAuth]

(2)登录验证接口

  • 仿照jwt的格式返回格式
  • 头部header:{'alg': "MD5", 'typ': "JWT"}
  • 载荷payload:{"pk": obj.pk, "username": obj.username}
  • 签名signature:将头部和载荷和django的密钥进行组合,使用MD5加密
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import User
import base64
import json
import hashlibclass LoginJWT(APIView):headers = {'alg': "MD5", 'typ': "JWT"}def post(self, request):# 获取数据username = request.data.get("username")password = request.data.get("password")# 检验数据if not all([username, password]):return Response({"code": 1001, "msg": '信息不全,请补全信息。'})obj = User.objects.filter(username=username, password=password).first()if not obj:return Response({"code": 1002, "msg": "登录信息校验失败。"})# 编码数据header = base64.b64encode(json.dumps(self.headers).encode('utf8'))payload = base64.b64encode(json.dumps({"pk": obj.pk, "username": obj.username}).encode('utf8'))md5 = hashlib.md5(header + payload + settings.SECRET_KEY.encode('utf8'))signature = base64.b64encode(md5.hexdigest().encode('utf8'))# 三个数据都是bytes类型,需要转换成字符串才能拼接jwt = '.'.join([i.decode('utf8') for i in [header, payload, signature]])return Response({"code": 1002, "msg": "登录成功", 'jwt': jwt})

(3)登录认证类

  • 需要注意的是字符串str和字节bytes的转换,不同的方法需要的不同
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from .models import User
from django.conf import settings
import json
import hashlib
import base64class JwtAuth(BaseAuthentication):def authenticate(self, request):# 获取jwtjwt = request.META.get("HTTP_JWT")if not jwt:raise AuthenticationFailed("请先登录再重试。")try:# 无法拆分成三个会报错,直接直接异常header, payload, signature = jwt.split('.')# 将头部、载荷和django的密钥进行整合后在加密md5 = hashlib.md5((header + payload + settings.SECRET_KEY).encode('utf8'))signature_ok = base64.b64encode(md5.hexdigest().encode('utf8')).decode('utf8')# 判断是否被串改数据if signature_ok == signature:user_dict = json.loads(base64.b64decode(payload))obj = User.objects.filter(**user_dict)return obj, jwtraise AuthenticationFailed("jwt信息验证失败。")except Exception as e:raise AuthenticationFailed("jwt信息有误。")

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring5深入浅出篇:JDK代理与CGLIB代理区别

Spring5深入浅出篇:JDK代理与CGLIB代理区别 很多粉丝私信我这个Spring5的课程在哪看,这边是在B站免费观看欢迎大家投币支持一下. https://www.bilibili.com/video/BV1hK411Y7zf JDK动态代理与CGLIB的区别 在Java的世界里&#xff0c;动态代理主要有两种实现方式&#xff1a;JDK…

【Python】基础知识(函数与数据容器)

笔者在C语言基础上学习python自用笔记 type() 返回数据类型 name "root" hei 1.8 wei 77 type_hei type(hei) type_wei type(wei) print(type(name)) print(type_hei) print(type_wei)在python中变量是没有类型的&#xff0c;它存储的数据是有类型的。 数据类…

Linux——界面和用户

本篇文章所写的都是基于centos 7 64位&#xff08;通过虚拟机运行&#xff09;。 一、Linux的界面 Linux操作系统提供了多种用户界面&#xff0c;主要分为图形用户界面&#xff08;GUI&#xff09;和命令行界面&#xff08;CLI&#xff09;。 1、图形用户界面(GUI)&#xff…

【大数据】LSM树,专为海量数据读写而生的数据结构

目录 1.什么是LSM树&#xff1f; 2.LSM树的落地实现 1.什么是LSM树&#xff1f; LSM树&#xff08;Log-Structured Merge Tree&#xff09;是一种专门针对大量写操作做了优化的数据存储结构&#xff0c;尤其适用于现代大规模数据处理系统&#xff0c;如NoSQL数据库&#xff…

Rsync数据同步实战:命令操作指南与最佳实践

&#x1f6a9;本文介绍 ​ 在本文中&#xff0c;我们不仅会介绍Rsync的基本概念和特点&#xff0c;还会详细解析Rsync命令的各个参数和选项&#xff0c;让读者能够灵活运用这些命令完成各种数据同步任务。无论您是数据管理员、系统工程师还是IT爱好者&#xff0c;只要您对Rsyn…

可解释的图像分类,提高组织表征的可信度论文速读

Explainable Image Classification with Improved Trustworthiness for Tissue Characterisation 摘要 机器学习模型进行组织表征可以帮助决策并指导安全的肿瘤切除。为了让外科医生信任该模型&#xff0c;需要提供生成的预测的可解释性。对于图像分类模型&#xff0c;像素归…

sudo的设置

sudo指令就是提高你的用户权限&#xff0c;用来完成root可以完成的工作&#xff0c;但是有一个前提&#xff0c;就是被root添加到信任名单中&#xff0c;接下来我们要讲解如何在root中添加用户到信任名单中。 在root中输入指令&#xff1a; 即可到达添加信用列表的位置&#x…

[图解敏捷口号]普天之下皆我妈-01-新手一次走两步

0 00:00:00,830 --> 00:00:03,750 今天我们来看一句敏捷口号 1 00:00:04,030 --> 00:00:05,660 后面我们会 2 00:00:06,300 --> 00:00:09,570 列一些比较幼稚的口号 3 00:00:09,970 --> 00:00:11,145 一句一句 4 00:00:11,145 --> 00:00:12,790 我们来剖析一…

软件3班20240424_2

package com.yanyu;import java.util.ResourceBundle;public class DBTest {// psvmpublic static void main(String[] args) { // 格式化 ctrl alt l // RBResourceBundle bundle ResourceBundle.getBundle("com/yanyu/db"); // CTRL a…

【注解】Mapper的注解 @Mapper、@Repository、@MapperScan

Mapper的注解 Mapper、Repository、MapperScan 一、Mapper1.1、主要作用1.2、示例 二、Repository2.1、主要作用2.2、示例2.3、注意事项 三、MapperScan Mapper 是 Mybatis 的注解&#xff0c;和 Spring 没有关系&#xff0c; Repository 是 Spring 的注解&#xff0c;用于声明…

勾八头歌之RNN

一、RNN快速入门 1.学习单步的RNN&#xff1a;RNNCell # -*- coding: utf-8 -*- import tensorflow as tf# 参数 a 是 BasicRNNCell所含的神经元数, 参数 b 是 batch_size, 参数 c 是单个 input 的维数&#xff0c;shape [ b , c ] def creatRNNCell(a,b,c):# 请在此添加代码…

【复现代码——环境配置】

目录 一、复现代码举例二、创建环境——选择一个Python版本2.1 创建基本环境2.1.1 基于AutoDL2.1.2 基于PyCharm 2.2 终端激活环境2.3 退出环境2.4 删除环境 三、PyTorch安装3.1 查看cuda3.2 安装PyTorch 四、其他依赖安装4.1 tensorboardX4.2 matplotlib4.3 medpy4.4 visdom4.…