ajax 视图上的 login_required 装饰器返回 401 而不是 302

Posted

技术标签:

【中文标题】ajax 视图上的 login_required 装饰器返回 401 而不是 302【英文标题】:login_required decorator on ajax views to return 401 instead of 302 【发布时间】:2012-04-19 08:01:53 【问题描述】:

在编写一些视图来响应 ajax 请求时,我发现 login_required 装饰器总是为未经过身份验证的用户返回 302 状态代码有点奇怪。由于这些视图是 ajax 视图,这似乎有些不合适。我不希望用户在这种情况下登录,但我希望 Django 告诉客户端访问这样的视图需要身份验证(我认为 401 应该是正确的状态代码)。

为了实现这一点,我开始编写自己的装饰器 login_required_ajax,但不知何故,这超出了我的技能范围。到目前为止,这是我想出的:

def login_required_ajax(function=None,redirect_field_name=None):
    """
    Just make sure the user is authenticated to access a certain ajax view

    Otherwise return a HttpResponse 401 - authentication required
    instead of the 302 redirect of the original Django decorator
    """
    def _decorator(view_func):
        def _wrapped_view(request, *args, **kwargs):
            if request.user.is_authenticated():
                return view_func(request, *args, **kwargs)
            else:
                return HttpResponse(status=401)

        if function is None:
            return _decorator
        else:
            return _decorator(function)

在视图上使用此装饰器时,只要我尝试访问网站上的任何页面,就会收到 ViewDoesNotExist 异常。

我首先认为问题可能是当用户未通过身份验证时直接返回 HttpResponse,因为响应对象不是可调用的。但是,只要我不尝试访问有问题的视图,装饰器就应该工作,不是吗?如果这真的是症结所在,我该如何编写一个装饰器来返回一个状态码为 401 的 HttpResponse?

【问题讨论】:

一个与您的主管无关的想法:您还可以引入一个中间件,该中间件检查请求是否为 ajax 请求,如果检测到视图返回 302,则返回 401用于登录...所以您可以继续使用 Django 的装饰器并处理不同的 ajax 和正常请求... 这听起来真的比“创建一个自定义装饰器并在 ajax 视图上使用它”更简单吗? ;) 【参考方案1】:

这是一个很好的尝试。以下是我发现的几个问题:

    您的_decorator 函数应返回_wrapped_viewif function is None 块的缩进有点偏离——login_required_ajax 函数需要返回修饰函数。

这是进行了这些更改的装饰器:

def login_required_ajax(function=None,redirect_field_name=None):
    """
    Just make sure the user is authenticated to access a certain ajax view

    Otherwise return a HttpResponse 401 - authentication required
    instead of the 302 redirect of the original Django decorator
    """
    def _decorator(view_func):
        def _wrapped_view(request, *args, **kwargs):
            if request.user.is_authenticated():
                return view_func(request, *args, **kwargs)
            else:
                return HttpResponse(status=401)
        return _wrapped_view

    if function is None:
        return _decorator
    else:
        return _decorator(function)

【讨论】:

像魅力一样工作。谢谢。

以上是关于ajax 视图上的 login_required 装饰器返回 401 而不是 302的主要内容,如果未能解决你的问题,请参考以下文章

带有 AJAX 的 Django login_required 装饰器

Django:使用@login_required 在视图上测试失败

Django @login_required 用于类视图

带有 login_required 装饰器的 Django 3.1 异步视图

如何从视图中删除“@oidc.login_required”以进行单元测试?

Django内置auth模块中login_required装饰器用于类视图的优雅方式