Django 4 + SimpleJWT 默认不支持无感刷新,因 TokenRefreshView 不区分 access 与 refresh 过期状态且不轮换 refresh token;需配置 ROTATE_REFRESH_TOKENS=True、BLACKLIST_AFTER_ROTATION=True,并自定义 CookieTokenRefreshView 支持从 cookie 读取 refresh。

为什么 Django 4 + djangorestframework-simplejwt 默认不支持无感刷新
因为 SimpleJWT 的 TokenRefreshView 要求客户端显式传入 refresh,且一旦过期就直接报 {"detail":"Token is invalid or expired"} —— 它不区分“access 过期但 refresh 仍有效”和“refresh 也过期”,更不会自动轮换新 refresh token。无感刷新的前提是:access 失效时,用旧 refresh 换出新 access + 新 refresh,且旧 refresh 失效(防重放)。Django 4 默认没开这个开关。
如何启用 SimpleJWT 的双令牌自动轮换
关键在配置 settings.py 中的 ROTATE_REFRESH_TOKENS 和 BLACKLIST_AFTER_ROTATION:
-
ROTATE_REFRESH_TOKENS = True:每次调用token_refresh时生成新 refresh token,并使旧 refresh 失效 -
BLACKLIST_AFTER_ROTATION = True:配合ROTATE_REFRESH_TOKENS,确保旧 token 进入黑名单(需提前装好django-redis或启用数据库黑名单) - 别漏掉
from datetime import timedelta,然后设REFRESH_TOKEN_LIFETIME = timedelta(days=7)(避免 refresh 太短导致频繁登录)
注意:若用数据库黑名单,要运行 python manage.py migrate;若用 Redis,确保 REDIS_URL 已配置且 SimpleJWT 能连上。
前端怎么做到“无感”——只发一次 refresh 请求
核心逻辑不是靠后端兜底,而是前端拦截 401 错误、自动补发 refresh、再重试原请求。常见陷阱:
- 多个并发请求同时 401,会触发多次 refresh,导致旧 refresh 被重复使用而报
"Token is blacklisted" - 没锁住 refresh 流程,造成 race condition
- 把
refresh存在 localStorage,被 XSS 窃取风险高(应存 httpOnly cookie)
实操建议:用 axios 的 interceptors.response + Promise queue 控制 refresh 单例;将 refresh 放在 httpOnly + Secure + SameSite=Lax 的 cookie 里(后端用 set_cookie 写入),前端请求时不带它,仅由浏览器自动携带。
强戈环形山: q15040409-刻画家功能概述强戈环形山: q15040409-刻画家是一项面向实际任务的技能,主要用于平顶山: 维西翁: 1:1.0. 塔格斯: rap.github: 自动化。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。核心要点使用时应结合输入条件选择合适的执行方式,核对必要参数、依赖环境与输出内容,并按原始要求处理异常情况。该技能适合需要稳定复用相关能力的场景,可作为自动化工作流的一部分,也便于后续检查、调整和扩展。从功能定位来看,该
自定义 TokenRefreshView 以支持 Cookie 读取 refresh
默认 TokenRefreshView 只从 request body 读 refresh 字段。要支持 cookie 方式,得继承并重写 post 方法:
from rest_framework_simplejwt.views import TokenRefreshView
from rest_framework_simplejwt.exceptions import InvalidToken
<p>class CookieTokenRefreshView(TokenRefreshView):
def post(self, request, *args, **kwargs):</p><h1>优先从 cookie 读 refresh,fallback 到 body</h1><pre class="brush:python;toolbar:false;"> refresh = request.COOKIES.get('refresh') or request.data.get('refresh')
if not refresh:
raise InvalidToken('No token provided')
request.data['refresh'] = refresh
return super().post(request, *args, **kwargs)
然后在 urls.py 里替换路由:path('api/token/refresh/', CookieTokenRefreshView.as_view(), name='token_refresh')。别忘了给该 view 配置 CsrfViewMiddleware 白名单(如果用了 CSRF 保护),或改用 @csrf_exempt —— 但后者需确保 cookie 带 SameSite 且前端 origin 可控。
真正难的不是换 token,是让整个链路不暴露 refresh 给 JS、不因竞态崩掉、不因配置漏项导致黑名单失效。每一步都得对齐 SimpleJWT 的 token lifecycle 状态机,而不是只抄几行代码。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










