Django自定义JWT中间件下request.user未填充问题求助
Django自定义JWT中间件赋值request.user后视图/装饰器无法获取的解决方法
核心问题分析
- DRF Request对象封装机制:你使用的
APIView属于Django REST Framework(DRF)组件,它会将Django原生HttpRequest包装为DRF的Request实例。DRF的Request.user属性由自身配置的认证类生成,而非直接继承原生request的user属性,这导致中间件给原生request赋值的user无法被DRF视图/装饰器识别。 - 中间件注册顺序错误:如果你的
JWTAuthenticationMiddleware放在Django自带的AuthenticationMiddleware之后,后者会根据session认证结果重置request.user为AnonymousUser,覆盖中间件的赋值。 - 装饰器判断逻辑偏差:装饰器中直接检查DRF封装后的
Request.user,而非中间件修改的原生request对象。
解决方案
方案一:改用DRF自定义认证类(推荐)
DRF本身提供完善的认证扩展机制,比自定义中间件更适配DRF生态:
- 编写DRF认证类:
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed import jwt from django.contrib.auth import get_user_model User = get_user_model() class JWTAuthentication(BaseAuthentication): def authenticate(self, request): auth_header = request.headers.get('Authorization') if not auth_header or not auth_header.startswith('Bearer '): return None # 不强制认证,交给后续认证类处理 token = auth_header.split(' ')[1] try: # 调用你的解码函数,确保返回包含用户标识的payload payload = decode_jwt_token(token) # 通过payload中的用户ID获取用户实例 user = User.objects.get(id=payload['user_id']) return (user, None) except jwt.ExpiredSignatureError: raise AuthenticationFailed('Token已过期') except jwt.DecodeError: raise AuthenticationFailed('无效的Token') except User.DoesNotExist: raise AuthenticationFailed('用户不存在')
- 在settings.py中配置DRF默认认证类:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'your_app.utils.JWTAuthentication', # 替换为你的认证类实际路径 # 如需保留session认证,可添加'django.contrib.auth.middleware.AuthenticationMiddleware' ], }
- 简化视图与装饰器:
DRF会自动处理认证逻辑,可移除自定义authorize装饰器,改用DRF自带权限类:
from rest_framework.permissions import IsAuthenticated class InviteUserView(APIView): permission_classes = [IsAuthenticated] # 自动检查用户是否认证 @bypass_csrf @role_required([UserRoleEnum.SUPER_ADMIN.value]) def post(self, request): print(f"DEBUG: User in request inside view - {request.user}") # ... 原有业务代码
方案二:修改中间件适配DRF Request对象
如果坚持使用中间件,需要同时修改原生request和DRF封装后的request的user属性:
class JWTAuthenticationMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): auth_header = request.headers.get("Authorization") if auth_header and auth_header.startswith("Bearer "): token = auth_header.split(" ")[1] try: user = decode_jwt_token(token) # 处理DRF封装的Request对象 if hasattr(request, '_request'): # 更新原生HttpRequest的user request._request.user = user request._request._force_auth_user = user # 同步DRF Request的user缓存 request.user = user else: # 原生HttpRequest直接赋值 request.user = user request._force_auth_user = user print(f"JWT Middleware: User assigned: {request.user.email} - {request.user.role}") except jwt.ExpiredSignatureError: print("JWT Middleware: Token expired") except jwt.DecodeError: print("JWT Middleware: Invalid token") response = self.get_response(request) return response
同时调整中间件注册顺序,将JWTAuthenticationMiddleware放在AuthenticationMiddleware之后:
# settings.py MIDDLEWARE = [ # ... 其他中间件 'django.contrib.auth.middleware.AuthenticationMiddleware', 'your_app.middleware.JWTAuthenticationMiddleware', # 放在AuthenticationMiddleware之后 # ... 其他中间件 ]
方案三:修改装饰器读取原生request对象
调整authorize装饰器的判断逻辑,直接读取原生HttpRequest的user属性:
def authorize(view_func): """Decorator to ensure that the user is authenticated via JWT.""" @functools.wraps(view_func) def wrapper(request, *args, **kwargs): # 获取原生Django HttpRequest对象 original_request = request._request if hasattr(request, '_request') else request if not hasattr(original_request, "user") or isinstance(original_request.user, AnonymousUser): return create_response( 401, ResponseCodes.UNAUTHORIZED.name, False, None, "Authentication required.", ResponseCodes.UNAUTHORIZED.value, ) # 同步DRF Request的user属性 if hasattr(request, 'user') and isinstance(request.user, AnonymousUser): request.user = original_request.user print(f"DEBUG: User in request - {request.user}") return view_func(request, *args, **kwargs) return wrapper
内容的提问来源于stack exchange,提问作者Nasir uddin Sabbir
相关产品推荐
相关产品推荐

