69. drf之jwt认证与base64编码解码

1. 基础概念

1.1 Base64

编码算法,不是加密。作用是把二进制数据转为可打印的 ASCII 字符串,可逆,任何人拿到字符串都可以解码得到原始内容,无保密性。JWT 内部使用 Base64URL(Base64 的变体)对头部、载荷做编码。

1.2 JWT(JSON Web Token)

JWT是一种用于身份认证和授权的开放标准(RFC 7519)。它基于JSON格式定义了一种安全的令牌,用于在客户端和服务器之间传输信息。

一种令牌格式,由三段字符串用.分隔:Header.Payload.Signature。

DRF 常用 djangorestframework-simplejwt 库实现 JWT 认证。

JWT由三部分组成:

Header(头部):描述令牌类型、签名算法,JSON → Base64URL 编码

       令牌类型通常为"JWT"。

          算法用于生成签名,例如HMAC、RSA或者ECDSA等。

示例:

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload(载荷):存放业务数据(用户 ID、过期时间等),JSON → Base64URL 编码

          载荷包含了关于用户或实体的声明和其他附加信息。
          JWT规范定义了一些标准的声明(例如:iss-签发者、exp-过期时间、sub-主题、aud-受众),并且允许自定义声明。

示例:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Signature:签名,Header+Payload 加盐加密生成,不做 Base64 解码,用于校验令牌是否被篡改

示例:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secretKey
)

重点:Header 和 Payload 只是 Base64URL 编码,可以直接解码查看内容,不能存放密码等敏感信息;签名用于防篡改,无法解码。

2. simplejwt

2.1 simplejwt工作步骤

1. 用户提交账号密码,后端校验账号合法
2. 后端构造 JWT Header、Payload,使用 Base64URL 分别编码两段
3. 使用配置的 SECRET_KEY + 指定算法(默认 HS256)对编码后的头部 + 载荷做签名
4. 拼接三段 Header.Payload.Signature,返回 access、refresh 令牌给前端
5. 前端后续请求在请求头携带 Authorization: Bearer <jwt_token>
6. DRF SimpleJWT 认证类处理:

  按.分割三段,Base64URL 解码 Header、Payload,读取过期时间、用户信息
  使用 SECRET_KEY 重新计算签名,和令牌自带签名对比,校验是否篡改
  校验通过后,把用户注入 request 对象,DRF 权限类继续校验;签名不匹配或过期直接拒绝访问

7. 后端接收到请求后,使用相同的密钥解析JWT,验证其有效性和完整性,然后运行对应的操作。

关键点:
解码 Payload 只是读取信息,不能用来验证令牌合法性;签名校验才是安全核心
Base64URL 只是格式转换,不是加密,Payload 不要存储手机号、密码等隐私

2.2 simplejwt开发步骤

[1] 第一部分:签发token

登录成功,就签发(后端校验通过生成token,返回给前端)

用户携带用户名和密码访问后端。
后端校验用户提供的用户名和密码是否正确。
如果校验通过,后端生成一个JWT Token,并将其返回给前端。
  JWT Token包含三个部分:Header、Payload和Signature。
前端收到JWT Token后,可以将其保存在本地
例如LocalStorage或者Cookie中,在后续需要使用Token的请求中携带它。

[2] 第二部分:token认证

用户访问需要登录后才能访问的接口,请求头中携带JWT Token。
后端从请求头中获取JWT Token。
后端对Token进行解析和验证,确保Token的完整性和真实性。
  验证Token的完整性可以通过验签来实现,即使用密钥对Token的签名部分进行验证(把 Header、Payload使用同样的加密方式进行加密,与Signature进行校验)。
  验证Token的真实性可以通过检查Token的有效期以及其他业务逻辑来实现。
如果Token验证通过,后端能够从Token的Payload部分获取到用户的相关信息,例如用户ID。
后端可以根据用户ID查询数据库或其他存储系统,获取该用户的详细信息。
后端将获取到的用户信息添加到请求的上下文中,以便后续的处理逻辑可以使用该信息进行权限控制、数据处理等操作。

3. base64

3.1 概念

base64编码是一种将二进制数据以文本形式表示的编码方式。
它将3个字节的二进制数据分割为4个6位的片段,然后将每个6位片段映射到一个可打印字符。
base64编码主要用于在传输过程中保存二进制数据,例如在电子邮件中传输二进制附件或在网页中嵌入图像。

3.1 base64编码与解码

编码:字符串 -> bytes -> base64 bytes -> str

解码:base64字符串 -> bytes -> 原始字符串

import json
import base64

# 编码
info = {'name': 'avril', 'age': 19, 'id': 6}
info_str = json.dumps(info)  # 转成json格式字符串
info_str_bytes = info_str.encode('utf-8')  # 字符串转换成bytes
res1 = base64.b64encode(info_str_bytes)  # 使用base编码
print(res1)  # b'eyJuYW1lIjogImF2cmlsIiwgImFnZSI6IDE5LCAiaWQiOiA2fQ=='
print(res1.decode('utf-8'))  # eyJuYW1lIjogImF2cmlsIiwgImFnZSI6IDE5LCAiaWQiOiA2fQ==

# 解码
res_bytes = base64.b64decode(res1)  # b64字符串转换成bytes
res_str = res_bytes.decode('utf-8')  # bytes转换成字符串
print(res_bytes)  # b'{"name": "avril", "age": 19, "id": 6}'
print(res_str)  # {"name": "avril", "age": 19, "id": 6}

3.2 Base64 与 Base64URL 的差异(JWT 使用 Base64URL)

[1] 概念

标准 Base64 有+ / =三个字符,在 URL、HTTP 请求头里会有转义冲突,Base64URL 做替换:

字符替换规则
+ -
/ _
= 直接删除(填充符)

解码时反向替换,再补=恢复标准 Base64 再解码。

[2] Python Base64URL 适配 JWT 示例

import base64

def b64url_encode(data: bytes) -> str:
    return base64.b64encode(data).rstrip(b'=').decode('utf-8').replace('+', '-').replace('/', '_')

def b64url_decode(s: str) -> bytes:
    s = s.replace('-', '+').replace('_', '/')
    padding = 4 - len(s) % 4
    if padding != 4:
        s += '=' * padding
    return base64.b64decode(s)

# 测试JWT头部
header_json = '{"alg":"HS256","typ":"JWT"}'
encoded = b64url_encode(header_json.encode("utf-8"))
print(encoded)
decoded = b64url_decode(encoded).decode("utf-8")
print(decoded)

4. 使用drf的simplejwt

4.1 概念

SimpleJWT 是 Django REST Framework 的 JWT 认证扩展库,用于实现基于 JSON Web Token 的无状态接口身份认证。
JWT 整体结构分为三部分:头部 (header)、载荷 (payload)、签名 (signature),三段之间用`.`分隔。

注意:JWT 的头部与载荷使用 base64url 编码,不是加密;签名部分用于校验数据是否被篡改。base64url 是 base64 的变种,把+替换为-,/替换为_,去掉末尾填充=。

SimpleJWT 默认提供两种令牌:

1. Access Token:访问令牌,有效期短,用于接口鉴权。
2. Refresh Token:刷新令牌,有效期更长,用于获取新的 Access Token。

认证步骤:

1. 用户提交账号密码,后端校验通过,生成 refresh + access 两个令牌返回客户端。
2. 客户端后续请求在请求头携带 Authorization: Bearer <access_token>。
3. DRF 的 JWT 认证后端解析 token,校验签名、过期时间,提取用户信息。
4. Access 过期后,客户端使用 refresh token 请求新令牌,无需重新登录。

settings.py配置

from datetime import timedelta

INSTALLED_APPS = [
    'rest_framework',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}

SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=15),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
    "ROTATE_REFRESH_TOKENS": False,
    "BLACKLIST_AFTER_ROTATION": True,
    "ALGORITHM": "HS256",
    "SIGNING_KEY": SECRET_KEY,
    "AUTH_HEADER_TYPES": ("Bearer",),
    "USER_ID_FIELD": "id",
    "USER_ID_CLAIM": "user_id",
}
配置项作用
ACCESS_TOKEN_LIFETIME access 令牌有效期
REFRESH_TOKEN_LIFETIME refresh 令牌有效期
ROTATE_REFRESH_TOKENS 刷新令牌时是否生成新 refresh
ALGORITHM 签名算法,HS256 对称加密,RS256 非对称
SIGNING_KEY 签名密钥,HS256 使用 django SECRET_KEY
AUTH_HEADER_TYPES 请求头前缀,默认 Bearer

4.2 安装

pip install djangorestframework-simplejwt

image

simplejwt的签发认证默认基于auth的user表

如果以auth作为用户表,就不再需要创建用户表,只要做迁移即可

4.3 签发认证代码实现

[1] 准备

django内置的auth-user表作为用户表---进行签发和认证

新建一个项目,配置数据库之后进行数据库迁移,生成内置的auth-user表

image

在运行manage.py任务创建一个超级用户

image

自动同步到数据库中

image

[2] 签发

签发只需要在路由中配置

在URL路由中添加登录接口路径,使用token_obtain_pair函数进行用户身份验证并签发JWT Token

以下总路由代码实现了登录接口

from django.contrib import admin
from django.urls import path
from rest_framework_simplejwt.views import token_obtain_pair

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', token_obtain_pair),  # 不需要再写登录接口
]

使用正确的用户名密码可以签发token

image

[3] 认证

(1) SimpleJWT 内置认证类

SimpleJWT 提供两个 DRF 标准认证类,均继承自rest_framework.authentication.BaseAuthentication,放在rest_framework_simplejwt.authentication模块。

认证类类路径核心特点适用场景
JWTAuthentication rest_framework_simplejwt.authentication.JWTAuthentication 校验 token 后,根据 payload 里 user_id 查询数据库,拿到真实 Django User 对象,赋值给 request.user 绝大多数业务场景,需要读取用户数据库字段、is_active、is_staff 等属性
JWTTokenUserAuthentication rest_framework_simplejwt.authentication.JWTTokenUserAuthentication 校验 token 后不查数据库,直接构造 TokenUser 虚拟用户对象,信息全部来自 token 载荷,无数据库 IO 跨服务 SSO、高并发场景,不依赖本地用户库;request.user 为 TokenUser 实例,只包含 token 内写入的字段

1. JWTAuthentication(默认推荐)

(1)从请求头提取 Authorization,剥离 Bearer 前缀,取出原始 token 字符串。
(2)校验 token 签名、过期时间、token 类型等声明,得到校验后的 payload。
(3)读取 payload 中的 user_id,查询 Django 用户表获取 User 实例。
(4)执行用户校验规则(默认校验 user.is_active=True)。
(5)返回 (user, validated_token),DRF 将 user 绑定到 request.user。

# 全局配置 settings.py
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ]
}

# 视图局部配置
from rest_framework_simplejwt.authentication import JWTAuthentication

class DemoView(APIView):
    authentication_classes = [JWTAuthentication]
    permission_classes = [IsAuthenticated]

2. JWTTokenUserAuthentication(无状态版本)
(1)提取并校验 token,逻辑和 JWTAuthentication 完全一致。
(2)不访问数据库,直接用 payload 实例化 TokenUser(虚拟用户模型)。
(3)TokenUser 只包含 token 内携带的字段,无法访问数据库用户模型的其他字段。
(4)request.user.is_authenticated 返回 True,但无法读取数据库额外属性。

关键区分要点

(1)JWTAuthentication:存在数据库查询开销,可以拿到完整用户模型,支持数据库层面用户状态校验。
(2)JWTTokenUserAuthentication:零数据库查询,性能更高;但 payload 一旦签发,用户状态变更(禁用账号)不会实时生效,直到 token 过期。
(3)TokenUser 对象没有数据库保存,仅为包装 payload 的只读对象。

(2) 代码准备

app01的views.py

from rest_framework.views import APIView
from rest_framework.response import Response

class BookView(APIView):
    def get(self, request):
        return Response('查询所有')

app01的urls.py

from django.urls import path
from .views import BookView

urlpatterns = [
    path('books/', BookView.as_view()),
]

总路由

from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import token_obtain_pair

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/app01/', include('app01.urls')),
    path('login/', token_obtain_pair),
]

不需要登录即可访问BookView接口

image

(3) 使用认证

需求:登录之后才能访问BookView接口,即要用到认证

给BookView接口加上认证类

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_simplejwt.authentication import JWTTokenUserAuthentication

class BookView(APIView):
    authentication_classes = [JWTTokenUserAuthentication]

    def get(self, request):
        return Response('查询所有')

此时不带参数仍然能直接访问BookView接口

根本原因:
  DRF中authentication_classes 仅负责身份识别,不负责访问拦截。
  认证类职责:尝试解析请求中的身份信息。
  权限类职责:判断当前用户是否允许访问接口。
  当前 BookView 仅配置 authentication_classes,未配置 permission_classes。

完整运行步骤:
  1. 客户端 GET 请求访问 /api/v1/app01/books/,请求头不带 token。
  2. DRF 调用 JWTTokenUserAuthentication.authenticate (request)。
  3. 请求不存在 Bearer token,该认证类返回 None。
  4. 认证列表运行完毕,无认证成功用户,request.user 赋值为 AnonymousUser 匿名用户。
  5. 视图未配置任何权限类,DRF 默认权限为 AllowAny,允许所有访问,不做拦截。
  6. 视图执行 get 方法,返回响应。

关键点:
JWTTokenUserAuthentication 检测到无 token 时返回 None,不会抛出 401。
认证类抛出 401 仅存在两种场景:
  ① 请求携带 token,但 token 过期、签名错误、格式非法。
  ② 自定义认证类手动抛出 AuthenticationFailed 异常。

Token 传递格式:
从 HTTP 请求头 Authorization 字段读取 token,格式: Authorization: Bearer <token 字符串>
Bearer 为认证方案标识,后面跟一个空格,空格之后是完整 JWT 字符串(header.payload.signature)

image

[4] 权限

(1) 概念

SimpleJWT 本身没有新增额外的权限类,权限体系用 DRF 原生权限组件。SimpleJWT 只提供认证类,负责解析 token、绑定 request.user;鉴权控制由 DRF 权限类完成。

DRF 原生常用权限类(搭配 SimpleJWT 使用)

权限类类路径作用
IsAuthenticated rest_framework.permissions.IsAuthenticated 仅认证通过用户可访问;匿名用户直接拒绝
IsAdminUser rest_framework.permissions.IsAdminUser 仅 is_staff=True 的管理员用户可访问
IsAuthenticatedOrReadOnly rest_framework.permissions.IsAuthenticatedOrReadOnly 认证用户可读写;匿名用户仅允许 GET/HEAD/OPTIONS
AllowAny rest_framework.permissions.AllowAny 全部请求放行,无论是否携带 token

1. 无 token 请求:认证类返回 None,request.user 为 AnonymousUser,IsAuthenticated 校验失败,返回 401。
2. token 非法 / 过期:认证类直接抛出 AuthenticationFailed,返回 401,不会进入权限校验阶段。
3. token 合法但权限不足:认证成功,进入权限校验,返回 403 Forbidden。

(2) 代码

为了解决配置认证类之后只识别身份信息不判断是否允许访问接口,需要搭配权限类

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_simplejwt.authentication import JWTTokenUserAuthentication
from rest_framework.permissions import IsAuthenticated

class BookView(APIView):
    authentication_classes = [JWTTokenUserAuthentication]
    permission_classes = [IsAuthenticated]
    def get(self, request):
        return Response('查询所有')

此时不登录不带token无法访问BookView接口

image

只有登录之后使用access token才能访问BookView接口,refresh token无法访问

image

image

4.4 双token认证

[1] 基础概念

(1) 定义

双 token 认证是 SimpleJWT 实现的 Access Token 加 Refresh Token 双令牌机制,用于平衡接口安全性与用户使用体验。
Access Token:访问令牌,有效期短,用于业务接口身份校验,泄露后的安全风险时间窗口小。
Refresh Token:刷新令牌,有效期更长,仅用于向服务端换取新的 Access Token,不能用于访问业务接口。

(2) 完整运行步骤

1 用户登录,账号密码校验通过,服务端同时返回 Access Token 与 Refresh Token。
2 客户端请求业务接口时,在请求头携带 Access Token,服务端完成 token 合法性校验。
3 Access Token 过期后,客户端携带 Refresh Token 调用 token 刷新接口,获取新 Access Token。
4 Refresh Token 过期后,用户必须重新登录获取令牌。

(3) 核心优缺点

优点
1 Access Token 有效期短,令牌被盗取后会快速失效,降低安全风险。
2 Access Token 过期时依靠 Refresh Token 刷新,用户无需反复登录,提升前端体验。
3 JWT 属于无状态令牌,服务端不需要存储令牌信息,无需维护会话数据表。

缺点
1 若 Refresh Token 泄露,攻击者可以持续刷新获取新 Access Token,直到 Refresh Token 过期。
2 原生 JWT 不支持直接作废已签发令牌,实现强制下线功能需要额外维护黑名单。

(4) 区别

令牌作用有效期使用场景
Access Token 业务接口身份认证 短(分钟级) 请求所有受保护 API
Refresh Token 仅刷新 access 令牌 长(天级) access 过期时调用刷新接口

[2] 代码--更新access

总路由

from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import token_obtain_pair, token_refresh

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/app01/', include('app01.urls')),
    path('login/', token_obtain_pair),  # 获取双token
    path('token/refresh/', token_refresh)  # 使用refresh换取新access
]

先使用登录接口获取两个token

image

带着生成的refresh即可刷新access

image

4.5 simple-jwt配置文件

在rest_framework_simplejwt的settings.py中即可以查看配置

DEFAULTS = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),  # Access Token的有效期
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),  # Refresh Token的有效期
    
    # 对于大部分情况,设置以上两项就可以了,以下为默认配置项目,可根据需要进行调整
    
    # 是否自动刷新Refresh Token
    'ROTATE_REFRESH_TOKENS': False,  
    # 刷新Refresh Token时是否将旧Token加入黑名单,如果设置为False,则旧的刷新令牌仍然可以用于获取新的访问令牌。需要将'rest_framework_simplejwt.token_blacklist'加入到'INSTALLED_APPS'的配置中
    'BLACKLIST_AFTER_ROTATION': False,  
    'ALGORITHM': 'HS256',  # 加密算法
    'SIGNING_KEY': settings.SECRET_KEY,  # 签名密匙,这里使用Django的SECRET_KEY
    # 如为True,则在每次使用访问令牌进行身份验证时,更新用户最后登录时间
    "UPDATE_LAST_LOGIN": False, 
    # 用于验证JWT签名的密钥返回的内容。可以是字符串形式的密钥,也可以是一个字典。
    "VERIFYING_KEY": "",
    "AUDIENCE": None,# JWT中的"Audience"声明,用于指定该JWT的预期接收者。
    "ISSUER": None, # JWT中的"Issuer"声明,用于指定该JWT的发行者。
    "JSON_ENCODER": None, # 用于序列化JWT负载的JSON编码器。默认为Django的JSON编码器。
    "JWK_URL": None, # 包含公钥的URL,用于验证JWT签名。
    "LEEWAY": 0, # 允许的时钟偏差量,以秒为单位。用于在验证JWT的过期时间和生效时间时考虑时钟偏差。
    # 用于指定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",
    # 用于指定可以使用的用户模型类。默认为"rest_framework_simplejwt.models.TokenUser"。
    "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",
    # JWT负载中包含JWT ID的声明。默认为"jti"。
    "JTI_CLAIM": "jti",
    # 在使用滑动令牌时,JWT负载中包含刷新令牌过期时间的声明。默认为"refresh_exp"。
    "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
    # 滑动令牌的生命周期。默认为5分钟。
    "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
    # 滑动令牌可以用于刷新的时间段。默认为1天。
    "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=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",
    # 用于列出或撤销已失效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",
}

如果需要修改配置,在项目的settings.py中修改即可

from datetime import timedelta
SIMPLE_JWT={
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),  # Access Token的有效期
    'REFRESH_TOKEN_LIFETIME': timedelta(days=7),  # Refresh Token的有效期
}

4.6 simplejwt定制登录返回格式

[1] 概念

SimpleJWT 默认的登录视图 TokenObtainPairView,返回格式固定为包含 access、refresh 两个字段的 json。

定制返回格式,核心方式是重写序列化器,自定义序列化器的输出字段,也可以继承视图类重写响应方法。

TokenObtainPairView 内部依赖 TokenObtainPairSerializer,登录校验成功后,序列化器的 data 属性就是返回给前端的数据。修改序列化器可以新增用户 id、用户名等自定义字段,修改返回结构。

[2] 步骤

1. 写个序列化组件,重写validate函数,函数返回什么,登录返回的格式就是什么

2. 配置文件中配置:替换为自定义的序列化器

SIMPLE_JWT={
        "TOKEN_OBTAIN_SERIALIZER": "app01.serializer.MyTokenObtainPairSerializer",
    }

[3] 代码--自定义序列化器

app01的serializer.py中,重写validate函数

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class DefTokenSerializer(TokenObtainPairSerializer):
    def validate(self, attrs):
        # 调用基类validate,完成账号密码校验,生成token
        data = super().validate(attrs)  # 仿照基类的写法    attrs是字典,里面包含前端 post 提交的所有字段,默认至少包含 username、password
        access = data.get('access')
        refresh = data.get('refresh')
        user = self.user  # 仿照基类写法
        return {'code': 100, 'msg': '登录成功', 'name': user.username, 'access': access, 'refresh': refresh}

前端提交数据 → 进入自定义类 validate → super 调用基类 validate(账号密码校验 + 生成 token)→ 拿到 data 字典 → 自定义类追加自定义字段 → 返回自定义字段。

项目的settings.py中,使用自定义的序列化器

SIMPLE_JWT = {
    "TOKEN_OBTAIN_SERIALIZER": "app01.serializer.DefTokenSerializer",
}

登录返回的格式

image

4.7 simplejwt更改荷载字段

[1] 概念

JWT 的荷载(payload)就是 token 内部存储的自定义数据。

payload 需要重写get_token函数,在生成 Token 对象的时候往荷载里添加 / 修改字段。

默认荷载自带字段:exp(过期时间)、iat(签发时间)、jti(token 唯一标识)。
TokenObtainPairSerializer 的 get_token 接收 user 对象,返回 RefreshToken 实例,荷载在这里组装。

[2] 步骤

1. 在自定义的序列化组件中重写get_token函数

2. 配置文件中使用自定义组件

[3] 代码

app01的serializer.py

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class DefTokenSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)  # 获取原生token荷载对象
        # 添加自定义荷载字段
        token['username'] = user.username
        return token

项目的settings.py

SIMPLE_JWT = {
    "TOKEN_OBTAIN_SERIALIZER": "app01.serializer.DefTokenSerializer",
}

登录返回token

image

查看荷载

import base64

# 需要在末尾加=才不报错,不足4位用=填充
a = base64.b64decode('eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzkwMzM1Nzk4LCJpYXQiOjE3OTAzMzU0OTgsImp0aSI6IjJiODcxYmY1NjUwOTQwNTY4YzM3NGIyZDU2YjIyZmQ3IiwidXNlcl9pZCI6IjEiLCJ1c2VybmFtZSI6ImF2cmlsIn0=')
print(a)

image

 

posted @ 2026-09-25 22:30  pythondjango  阅读(2)  评论(0)    收藏  举报