Django搭配REST框架、SimpleJWT时自定义中间件user始终为匿名如何解决
问题原因
- Django自带的
AuthenticationMiddleware仅会处理session认证场景下的用户身份填充,而rest_framework_simplejwt的JWT token校验逻辑属于DRF框架的视图层逻辑,默认会在请求匹配到路由、进入对应视图之前才执行,中间件执行时该校验还未触发,因此request.user始终是未认证的匿名用户。 - 若自定义中间件放在了
AuthenticationMiddleware之前,连session场景下的已认证用户也无法识别,同样会触发该问题。
解决方案
方案1:改用DRF自定义认证类实现(推荐)
该方案贴合DRF的请求生命周期,无额外重复校验开销,直接继承SimpleJWT的JWTAuthentication类,在认证成功后更新字段即可:
from rest_framework_simplejwt.authentication import JWTAuthentication from django.utils.timezone import now class UpdateLastRequestJWTAuthentication(JWTAuthentication): def authenticate(self, request): auth_result = super().authenticate(request) # 仅认证成功时更新字段 if auth_result is not None: user, validated_token = auth_result user.last_request = now() # 加update_fields减少数据库写入开销 user.save(update_fields=['last_request']) return user, validated_token return None
之后在项目配置文件中替换默认的JWT认证类:
# settings.py REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( '你存放该类的模块路径.UpdateLastRequestJWTAuthentication', # 其他原有认证类保留即可 ) }
如果同时兼容session等其他认证方式,对应重写对应认证类的authenticate方法添加更新逻辑即可。
方案2:中间件内主动解析JWT(必须使用中间件的场景)
如果业务逻辑要求必须通过中间件实现,可以在中间件内手动解析请求头的JWT token,提前完成身份校验:
from django.utils.timezone import now from rest_framework_simplejwt.exceptions import InvalidToken, TokenError from rest_framework_simplejwt.tokens import AccessToken class LastRequestMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): # 从请求头提取JWT token auth_header = request.META.get('HTTP_AUTHORIZATION', '') if auth_header.startswith('Bearer '): token_str = auth_header.split(' ')[1] try: access_token = AccessToken(token_str) user = access_token.get_user() user.last_request = now() user.save(update_fields=['last_request']) # 可选:将解析到的用户赋值给request,供后续逻辑复用 request.user = user except (InvalidToken, TokenError): # token无效直接跳过即可 pass response = self.get_response(request) return response
该方案的中间件仅需要放在CommonMiddleware之后即可,不依赖AuthenticationMiddleware。
内容的提问来源于stack exchange,提问作者sandders_on
相关产品推荐
相关产品推荐

