You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Simple-JWT中自动刷新Access Token及Token存储问题

Django Simple-JWT 自动刷新Access Token及Refresh Token请求头配置

一、Refresh Token的请求头配置

默认情况下simple-jwt从请求体获取Refresh Token,要改为从请求头传递,需自定义刷新序列化器:

1. 自定义TokenRefreshSerializer

from rest_framework_simplejwt.serializers import TokenRefreshSerializer
from rest_framework_simplejwt.exceptions import InvalidToken

class CustomTokenRefreshSerializer(TokenRefreshSerializer):
    def validate(self, attrs):
        # 优先从自定义请求头X-Refresh-Token获取Refresh Token
        refresh_token = self.context['request'].headers.get('X-Refresh-Token')
        if not refresh_token:
            # 兼容原有请求体传参的方式
            refresh_token = attrs.get('refresh')
        
        if not refresh_token:
            raise InvalidToken("Refresh token not provided")
        
        attrs['refresh'] = refresh_token
        return super().validate(attrs)

2. 替换默认刷新端点

在项目urls.py中更新刷新Token的路由,使用自定义序列化器:

from rest_framework_simplejwt.views import TokenRefreshView
from .serializers import CustomTokenRefreshSerializer

urlpatterns = [
    # 其他路由...
    path('api/token/refresh/', TokenRefreshView.as_view(serializer_class=CustomTokenRefreshSerializer), name='token_refresh'),
]

此后前端发送刷新请求时,可将Refresh Token放在X-Refresh-Token请求头中,无需再放在请求体。

二、实现Access Token过期自动刷新并执行原请求

通过自定义中间件拦截认证失败的请求,尝试用Refresh Token刷新Access Token,再重新执行原请求:

1. 编写自动刷新中间件

from django.http import JsonResponse
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.exceptions import AuthenticationFailed, ExpiredSignatureError
from rest_framework_simplejwt.serializers import TokenRefreshSerializer

class JWTAutoRefreshMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 排除刷新Token的端点,避免循环调用
        if request.path == '/api/token/refresh/':
            return self.get_response(request)
        
        auth_header = request.headers.get('Authorization')
        refresh_token = request.headers.get('X-Refresh-Token')
        
        # 仅当同时携带Access Token和Refresh Token时处理
        if auth_header and auth_header.startswith('Bearer ') and refresh_token:
            try:
                # 尝试用原Access Token认证
                auth = JWTAuthentication()
                user, token = auth.authenticate(request)
            except ExpiredSignatureError:
                # Access Token过期,尝试刷新
                try:
                    refresh_serializer = TokenRefreshSerializer(
                        data={'refresh': refresh_token}, 
                        context={'request': request}
                    )
                    refresh_serializer.is_valid(raise_exception=True)
                    new_access_token = refresh_serializer.validated_data['access']
                    
                    # 更新请求头中的Access Token
                    request.META['HTTP_AUTHORIZATION'] = f'Bearer {new_access_token}'
                    # 重新认证并绑定用户到请求对象
                    auth = JWTAuthentication()
                    user, token = auth.authenticate(request)
                    request.user = user
                except AuthenticationFailed:
                    # Refresh Token无效,返回401
                    return JsonResponse({'detail': '无效或过期的Refresh Token'}, status=401)
            except AuthenticationFailed:
                # Access Token无效(非过期),返回401
                return JsonResponse({'detail': '无效的Access Token'}, status=401)
        
        # 执行原请求
        response = self.get_response(request)
        
        # 将新的Access Token通过响应头返回给前端,方便前端更新存储
        if 'new_access_token' in locals():
            response['X-New-Access-Token'] = new_access_token
        
        return response

2. 注册中间件

在settings.py的MIDDLEWARE列表中添加自定义中间件,注意要放在AuthenticationMiddleware之后:

MIDDLEWARE = [
    # 其他中间件...
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'your_app_name.middleware.JWTAutoRefreshMiddleware',  # 替换为你的应用路径
    # 其他中间件...
]

三、关键注意事项

  • 前端需监听响应头的X-New-Access-Token,更新本地存储的Access Token,避免后续请求仍使用过期Token。
  • 确保Refresh Token的有效期配置合理(在settings.py的SIMPLE_JWT中设置REFRESH_TOKEN_LIFETIME),同时可启用Refresh Token旋转(ROTATE_REFRESH_TOKENS = True),避免重复使用同一Refresh Token。
  • 若Refresh Token过期或被撤销,后端会返回401,前端需引导用户重新登录。

内容的提问来源于stack exchange,提问作者chocho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 12:43:24