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

Django中间件无法获取登录用户名的问题及方案咨询

Django中间件中无法获取request.user.username的问题

问题背景

我尝试在以下Django中间件中获取request.user.username:

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

    def __call__(self, request):
        response = self.get_response(request)
        user_id = request.user.username
        # ... 

我已确保MyMiddleware在settings.py中位于SessionMiddleware和AuthenticationMiddleware之后:

MIDDLEWARE = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    # ...
    'my_app.my_py_file.MyMiddleware'
)

但request.user.username仍为空字符串。


Q1. 这是为什么?

我还尝试添加@authentication_classes([TokenAuthentication,]):

from rest_framework.authentication import TokenAuthentication # <--
from rest_framework.decorators import authentication_classes # <--

@authentication_classes([TokenAuthentication,]) # <--
class MyMiddleware():
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        user_id = request.user.username
        # ... 

但没有效果。

我还尝试让类继承APIView(尽管中间件不是REST API,这看起来很不合理):

from rest_framework.authentication import TokenAuthentication # <--
from rest_framework.views import APIView # <--

class MyMiddleware(APIView): # <-- 
    authentication_classes = [TokenAuthentication] # <--
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        user_id = request.user.username
        # ... 

仍然无效。

之后我看到一种说法:

如果你使用simple_jwt,无法在中间件中直接使用request.user,因为认证机制在视图函数中运行。因此你需要在中间件中手动认证,之后才能使用request.user获取用户模型中的数据。

该方案使用了rest_framework_simplejwt,它不属于Django框架,需要单独安装。

目前我能在中间件中获取用户名的唯一方法是参考一种方案,修改后的中间件如下:

from re import sub
from rest_framework.authtoken.models import Token

class MyMiddleware(object):

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


    def __call__(self, request):
        response = self.get_response(request)
        user_id = request.user.username

        if not user_id: 
            user_id = self.getUsername(request)
        
        # ...
    
    def getUsername(self, request):
        header_token = request.META.get('HTTP_AUTHORIZATION', None)
        if header_token is not None:
            try:
                token = sub('Token ', '', header_token)
                token_obj = Token.objects.get(key = token)
            except Token.DoesNotExist:
                pass
        return token_obj.user.username

Q2. 这是不安装第三方库的情况下,在中间件中获取用户名的唯一且正确的方法吗?


更新

以下是我的CustomUser类及相关方法create_custom_user():

class CustomUser(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    # 一些应用特定字段    

@receiver(post_save, sender=User)
@debugger_queries
def create_custom_user(sender, **kwargs):
    instance = kwargs['instance']
    if kwargs['created']:  # 创建
        CustomUser.objects.get_or_create(user=instance)

回答

针对Q1:为什么request.user.username为空

  1. 认证时机不匹配:Django自带的AuthenticationMiddleware仅处理基于Session的Web登录认证。如果你的接口用的是DRF的TokenAuthentication这类token认证,DRF的认证逻辑是在视图层执行的,中间件运行时视图还未处理,此时request.user还是匿名用户(AnonymousUser),所以username为空。
  2. 视图层配置对中间件无效:@authentication_classes装饰器和APIView都是DRF视图专属的机制,中间件不属于视图范畴,这些配置对中间件完全不起作用,因此你的尝试没有效果。

针对Q2:不装第三方库的情况下是否有其他方法

你当前手动解析Token的方法可行,但不是唯一方案,还有更规范的实现方式:

方法1:复用DRF的TokenAuthentication逻辑

直接调用DRF的认证类完成验证,避免自己写正则解析token,减少出错概率:

from rest_framework.authentication import TokenAuthentication
from rest_framework.exceptions import AuthenticationFailed

class MyMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.auth = TokenAuthentication()

    def __call__(self, request):
        # 认证逻辑要放在调用get_response之前执行
        try:
            user, token = self.auth.authenticate(request)
            if user:
                request.user = user
        except AuthenticationFailed:
            # 认证失败时保持request.user为匿名用户,不影响后续流程
            pass
        
        response = self.get_response(request)
        # 此时可正常获取request.user.username
        user_id = request.user.username
        # ...
        return response

方法2:完善自定义Token认证逻辑

如果不想依赖DRF的认证类,可自己实现,但要补充异常处理(避免token不存在时引发报错):

from re import sub
from rest_framework.authtoken.models import Token

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

    def __call__(self, request):
        self.authenticate(request)
        response = self.get_response(request)
        user_id = request.user.username
        # ...
        return response

    def authenticate(self, request):
        header_token = request.META.get('HTTP_AUTHORIZATION', '')
        if not header_token.startswith('Token '):
            return
        try:
            token_key = sub('^Token ', '', header_token)
            token_obj = Token.objects.get(key=token_key)
            request.user = token_obj.user
        except Token.DoesNotExist:
            # token不存在时不修改request.user,保持匿名状态
            pass

注意要把认证逻辑放在get_response(request)之前,这样后续视图和其他中间件也能使用已认证的用户信息。

额外说明

你的CustomUser是基于Django自带User的一对一扩展,这和中间件获取用户名的问题无关,只要token_obj.user能关联到正确的User实例,就能正常获取username。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 18:33:16