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

Django自定义JWT中间件下request.user未填充问题求助

Django自定义JWT中间件赋值request.user后视图/装饰器无法获取的解决方法

核心问题分析

  1. DRF Request对象封装机制:你使用的APIView属于Django REST Framework(DRF)组件,它会将Django原生HttpRequest包装为DRF的Request实例。DRF的Request.user属性由自身配置的认证类生成,而非直接继承原生request的user属性,这导致中间件给原生request赋值的user无法被DRF视图/装饰器识别。
  2. 中间件注册顺序错误:如果你的JWTAuthenticationMiddleware放在Django自带的AuthenticationMiddleware之后,后者会根据session认证结果重置request.user为AnonymousUser,覆盖中间件的赋值。
  3. 装饰器判断逻辑偏差:装饰器中直接检查DRF封装后的Request.user,而非中间件修改的原生request对象。

解决方案

方案一:改用DRF自定义认证类(推荐)

DRF本身提供完善的认证扩展机制,比自定义中间件更适配DRF生态:

  1. 编写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('用户不存在')
  1. 在settings.py中配置DRF默认认证类:
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'your_app.utils.JWTAuthentication',  # 替换为你的认证类实际路径
        # 如需保留session认证,可添加'django.contrib.auth.middleware.AuthenticationMiddleware'
    ],
}
  1. 简化视图与装饰器:
    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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 10:33:21