eagleye

Django REST Framework Simple JWT 访问令牌与刷新令牌实践指南

Django REST Framework Simple JWT 访问令牌与刷新令牌实践指南

一、概述

djangorestframework-simplejwt是 Django REST Framework (DRF) 的 JWT 认证扩展库,通过访问令牌 (Access Token)刷新令牌 (Refresh Token)实现无状态、高安全性的用户认证。本文详细解析两类令牌的核心机制、安全配置及最佳实践,帮助开发者在实际项目中正确使用。

二、核心概念:访问令牌与刷新令牌

2.1 访问令牌(Access Token)

作用

  • 短期凭证:用于直接访问受保护的 API 端点(如用户信息、支付接口)。
  • 身份验证:服务器通过验证令牌签名确认用户身份,无需查询数据库。
  • 时效性短:默认有效期 5 分钟(可配置为 5-15 分钟),降低泄露风险。
  • 无状态性:包含用户信息(如 ID、角色)在 JWT Payload 中,服务端仅验证签名。
  • 传输方式:通过 HTTP 请求头传递:Authorization: Bearer <access_token>

特点

生成流程

用户登录时,服务器验证用户名/密码后生成访问令牌。示例负载(Payload):

{

"token_type": "access", // 令牌类型

"exp": 1714675200, // 过期时间戳(2024-05-03 00:00:00)

"iat": 1714674900, // 签发时间戳(2024-05-02 23:55:00)

"jti": "a1b2c3d4-5678-90ef-ghij-klmnopqrstuv", // 唯一标识(防重放攻击)

"user_id": 42, // 用户 ID(关键标识)

"username": "john_doe", // 用户名(可选自定义字段)

"role": "editor" // 自定义声明(如用户角色)

}

2.2 刷新令牌(Refresh Token)

作用

  • 令牌续签:当访问令牌过期时,使用刷新令牌获取新的访问令牌,避免用户重复登录。
  • 长期会话管理:默认有效期 1 天(可配置为 1-30 天),平衡安全性与用户体验。
  • 不直接访问资源:仅用于调用/token/refresh/接口获取新令牌。
  • 安全存储:需客户端安全存储(如HttpOnly Cookie、设备安全存储),防止泄露。
  • 可选轮换机制:启用ROTATE_REFRESH_TOKENS后,每次刷新生成新刷新令牌,旧令牌失效。

特点

刷新流程

1. 客户端发送刷新请求:POST /api/token/refresh/

Content-Type: application/json

{

"refresh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTcxNDc2MTYwMCwiaWF0IjoxNzE0Njc1MjAwLCJqdGkiOiJiM2U0ZjU2Ny04OTBqLTExZTktYjViNS0wMjQyYWMxMzBlZjQiLCJ1c2VyX2lkIjo0Mn0.abc123xyz"

}

2. 服务器验证刷新令牌有效性,返回新令牌(若启用轮换,包含新刷新令牌):{

"access": "new_access_token_here",

"refresh": "new_refresh_token_here" // 仅当 ROTATE_REFRESH_TOKENS=True 时返回

}

三、核心安全机制与配置

3.1 令牌有效期控制

通过SIMPLE_JWT配置调整令牌生命周期,平衡安全性与用户体验。

令牌类型

默认有效期

配置参数

推荐范围

访问令牌

5 分钟

ACCESS_TOKEN_LIFETIME

5-15 分钟

刷新令牌

1 天

REFRESH_TOKEN_LIFETIME

1-7 天(敏感系统更短)

示例配置(settings.py)

from datetime import timedelta

SIMPLE_JWT = {

# 调整有效期

"ACCESS_TOKEN_LIFETIME": timedelta(minutes=15), # 访问令牌 15 分钟过期

"REFRESH_TOKEN_LIFETIME": timedelta(days=3), # 刷新令牌 3 天过期

}

3.2 防止令牌滥用

黑名单机制(Blacklisting)

启用后,旧刷新令牌在轮换后加入黑名单,防止重复使用。需安装djangorestframework-simplejwt-token-blacklist应用。

配置

SIMPLE_JWT = {

"ROTATE_REFRESH_TOKENS": True, # 每次刷新生成新刷新令牌

"BLACKLIST_AFTER_ROTATION": True, # 旧刷新令牌加入黑名单

"BLACKLIST_TOKEN_CHECKS": [

"rest_framework_simplejwt.token_blacklist.blacklist.check_blacklisted" # 黑名单检查函数

],

}

签名验证

通过加密算法(如HS256或RS256)确保令牌未被篡改:

  • 对称加密(HS256):使用同一密钥签名和验证(适合单服务场景)。
  • 非对称加密(RS256):私钥签名、公钥验证(适合多服务/跨域场景)。

配置示例HS256):

SIMPLE_JWT = {

"ALGORITHM": "HS256", # 加密算法

"SIGNING_KEY": os.getenv("JWT_SECRET_KEY"), # 从环境变量获取密钥(64+字符随机字符串)

"VERIFYING_KEY": None, # 对称加密无需公钥

}

四、完整认证流程

sequenceDiagram

participant Client

participant Server

Client->>Server: 发送登录请求(用户名/密码)

Server->>Client: 返回 access_token + refresh_token

loop 访问受保护资源

Client->>Server: 发送 API 请求(携带 access_token)

Server->>Client: 返回资源数据

end

alt access_token 过期

Client->>Server: 发送刷新请求(携带 refresh_token)

Server->>Client: 返回新 access_token(+ 新 refresh_token)

end

五、最佳实践

5.1 客户端存储策略

  • 访问令牌:存储在内存或sessionStorage(浏览器关闭即失效),避免localStorage(防 XSS 攻击)。
  • 刷新令牌:使用HttpOnly + Secure Cookie存储(防 XSS 和中间人攻击),或设备级安全存储(如 iOS Keychain、Android Keystore)。

5.2 自定义令牌负载

通过继承TokenObtainPairSerializer添加用户自定义信息(如邮箱、角色)到令牌中。

示例代码

# serializers.py

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

from rest_framework_simplejwt.tokens import RefreshToken

class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):

@classmethod

def get_token(cls, user):

"""添加自定义声明到令牌"""

token = super().get_token(user)

# 自定义字段(根据用户模型添加)

token["email"] = user.email

token["role"] = user.role # 假设用户模型有 role 字段

token["is_staff"] = user.is_staff

return token

5.3 敏感操作增强

对支付、删除账户等敏感操作,使用短有效期访问令牌(如 5 分钟),降低泄露风险。

配置

SIMPLE_JWT = {

"ACCESS_TOKEN_LIFETIME": timedelta(minutes=5), # 敏感操作缩短为 5 分钟

}

六、常见问题与解决方案

Q1: 刷新令牌泄露怎么办?

  • 立即失效:通过黑名单机制将泄露的刷新令牌加入黑名单(需启用BLACKLIST_AFTER_ROTATION)。
  • 缩短有效期:将REFRESH_TOKEN_LIFETIME设为更短(如 1 天),减少攻击窗口。
  • 客户端:删除本地存储的访问令牌和刷新令牌。
  • 服务端:将用户的所有有效刷新令牌加入黑名单(需自定义逻辑遍历并标记)。
  • 最小化攻击窗口:即使令牌被截获,攻击者仅有几分钟时间滥用。
  • 无状态补偿JWT 无法实时失效(如用户退出登录),短有效期是弥补无状态缺陷的关键措施。

Q2: 如何主动注销用户?

Q3: 为何访问令牌有效期要短?

七、总结

djangorestframework-simplejwt通过访问令牌与刷新令牌的协同工作,为 DRF API 提供了安全、高效的认证方案。核心实践包括:

  • 短有效期访问令牌降低泄露风险;
  • 刷新令牌结合轮换与黑名单机制管理长期会话;
  • 自定义负载和安全存储策略增强灵活性与安全性。

通过合理配置和最佳实践,开发者可在用户体验与系统安全间取得平衡,构建符合企业级标准的认证体系。

 

posted on 2025-07-01 16:51  GoGrid  阅读(277)  评论(0)    收藏  举报

导航