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

Django会话过期后,自定义login_required装饰器如何返回401响应?

问题

我编写了如下自定义login_required装饰器:

def login_required(function):
    """
    Ensure that user is logged in
    """

    def wrap(request, *args, **kwargs):
        if request.user.is_anonymous:
            message = {
                "status": "error",
                "message": "user login error",
                "data": "user is not logged in",
            }
            return HttpResponse(
                content=json.dumps(message).encode("utf-8"),
                status=401,
                headers=None,
                content_type="application/json",
            )
        return function(request, *args, **kwargs)

    return wrap

当请求到来且Django会话过期时,我能在响应中看到自定义消息,但响应状态码为302,会重定向到带有/accounts/login/?next=的URL。

我已在settings中配置了SESSION_TIMEOUT_REDIRECT、LOGOUT_REDIRECT、LOGIN_URL,尝试过调整不同Django设置但未解决问题。

当前使用的中间件如下:

MIDDLEWARE = [
    "csp.middleware.CSPMiddleware",
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django_session_timeout.middleware.SessionTimeoutMiddleware",
    "corsheaders.middleware.CorsMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    "whitenoise.middleware.WhiteNoiseMiddleware",
    "core.middleware.admin_pages_middleware.AdminPagesMiddleware",
]

技术栈:

  • Python 3.12
  • Django 5.0

我希望响应返回401而非302,请问我遗漏了什么配置?

解决方案

1. 修正django_session_timeout中间件配置

你使用的django_session_timeout.middleware.SessionTimeoutMiddleware优先级高于自定义装饰器,会话过期时会自动触发重定向到LOGIN_URL,覆盖了你返回401的逻辑。

在settings.py中设置:

SESSION_TIMEOUT_REDIRECT = None

该配置会让中间件在会话过期时不主动重定向,交由你的装饰器处理响应。

2. 避免与Django自带login_required混用

确认你的视图仅使用自定义的login_required装饰器,不要和Django自带的django.contrib.auth.decorators.login_required混用——自带装饰器默认会对未登录请求返回302重定向。

3. 强制清除重定向响应头

在自定义装饰器中,添加逻辑清除可能触发重定向的Location头,确保401响应不被篡改:

def login_required(function):
    """
    Ensure that user is logged in
    """
    def wrap(request, *args, **kwargs):
        if request.user.is_anonymous:
            message = {
                "status": "error",
                "message": "user login error",
                "data": "user is not logged in",
            }
            response = HttpResponse(
                content=json.dumps(message).encode("utf-8"),
                status=401,
                content_type="application/json",
            )
            # 清除可能存在的重定向头
            response.pop('Location', None)
            return response
        return function(request, *args, **kwargs)
    return wrap

4. 检查自定义中间件AdminPagesMiddleware

排查core.middleware.admin_pages_middleware.AdminPagesMiddleware的代码,确认该中间件没有拦截未登录请求并触发重定向的逻辑——如果存在相关逻辑,需要调整其优先级或修改判断条件,避免覆盖401响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 12:12:32