如何在Django Admin中基于simple JWT实现access_token自动刷新
服务端实现Django simple JWT自动刷新access_token方案
实现核心思路
因为JWT本身是无状态协议,默认服务端不会主动处理token刷新,要实现服务端自动刷新需要依赖Cookie存储token,配合自定义验证类和中间件完成逻辑:
- 开启simple JWT的Cookie存储配置,将access、refresh token都存入HttpOnly Cookie,服务端可直接读取
- 自定义JWT验证类,捕获access_token过期异常后,自动校验refresh_token有效性,生成新的access_token
- 新增响应中间件,将新生成的access_token写入响应Cookie返回给客户端
具体实现步骤
1. 配置simple JWT参数
在settings.py中添加如下配置:
INSTALLED_APPS = [ # 其余原有应用 'rest_framework', 'rest_framework_simplejwt', 'rest_framework_simplejwt.token_blacklist', # 可选,用于过期token拉黑 ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( # 替换默认JWT验证类为自定义类 '你的应用名.authentication.CustomJWTAuthentication', ) } from datetime import timedelta SIMPLE_JWT = { # 按需调整token有效期 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), # 开启Cookie存储配置 'AUTH_COOKIE': 'access_token', 'AUTH_COOKIE_REFRESH': 'refresh_token', 'AUTH_COOKIE_HTTPONLY': True, 'AUTH_COOKIE_SECURE': True, # 生产环境必须开启 'AUTH_COOKIE_SAMESITE': 'Lax', # 可选,开启refresh token轮换,提升安全性 'ROTATE_REFRESH_TOKENS': True, 'BLACKLIST_AFTER_ROTATION': True, }
2. 自定义JWT身份验证类
在你的应用目录下新建authentication.py文件:
from rest_framework_simplejwt.authentication import JWTAuthentication from rest_framework_simplejwt.exceptions import InvalidToken, TokenError from rest_framework_simplejwt.tokens import RefreshToken from django.conf import settings class CustomJWTAuthentication(JWTAuthentication): def authenticate(self, request): # 先走默认验证逻辑校验access_token try: return super().authenticate(request) except InvalidToken as e: # 仅处理access_token过期的场景 if "token is expired" not in str(e.detail): return None # 读取Cookie中的refresh_token refresh_token = request.COOKIES.get(settings.SIMPLE_JWT.get('AUTH_COOKIE_REFRESH', 'refresh_token')) if not refresh_token: return None try: # 校验refresh_token有效性 refresh = RefreshToken(refresh_token) # 生成新的access_token new_access_token = str(refresh.access_token) # 写入请求对象,供后续中间件处理 request._new_access_token = new_access_token # 替换请求Cookie中的旧access_token,重新走验证逻辑 request.COOKIES[settings.SIMPLE_JWT.get('AUTH_COOKIE', 'access_token')] = new_access_token return super().authenticate(request) except TokenError: # refresh_token也已过期,直接返回验证失败 return None
3. 新增响应中间件同步新token到Cookie
在应用目录下新建middleware.py文件:
from django.conf import settings class AutoRefreshTokenMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) # 检测是否有新生成的access_token需要写入响应 if hasattr(request, '_new_access_token'): response.set_cookie( settings.SIMPLE_JWT.get('AUTH_COOKIE', 'access_token'), request._new_access_token, expires=settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME'], httponly=settings.SIMPLE_JWT['AUTH_COOKIE_HTTPONLY'], secure=settings.SIMPLE_JWT['AUTH_COOKIE_SECURE'], samesite=settings.SIMPLE_JWT['AUTH_COOKIE_SAMESITE'], ) return response
将中间件添加到settings.py的MIDDLEWARE列表中,放在CommonMiddleware之后即可:
MIDDLEWARE = [ # 其余原有中间件 'django.middleware.common.CommonMiddleware', '你的应用名.middleware.AutoRefreshTokenMiddleware', ]
4. Django Admin适配
如果需要给Django Admin本身也启用该逻辑,自定义Admin登录视图,在登录成功后将access、refresh token写入响应Cookie即可。
注意事项
- 该方案依赖Cookie存储token,仅适用于同域部署场景,跨域场景下需要额外配置跨域Cookie规则
- 若开启refresh token轮换,需要配置
rest_framework_simplejwt.token_blacklist应用并执行迁移 - 跨域前后端分离场景下,该方案的兼容性不如前端Axios拦截器方案,优先推荐前端实现
内容的提问来源于stack exchange,提问作者Lutaaya Huzaifah Idris
相关产品推荐
相关产品推荐

