使用错误凭据的 Django 登录返回 200 而不是 401

Posted

技术标签:

【中文标题】使用错误凭据的 Django 登录返回 200 而不是 401【英文标题】:Django login with wrong credentials returns 200 not 401 【发布时间】:2014-11-08 11:18:41 【问题描述】:

这是一个非常直接的测试,但我似乎做错了。

我想检查哪些用户可以登录并执行操作(这是更大的测试套件的一部分),但第一步会导致一些问题。

class SuperUserTest(TestCase):
    def setUp(self):
        self.client = Client()
        self.su = User.objects.create_superuser('super','','the_correct_password')
    def test_su_can_login(self):
        response = self.client.post(reverse('django.contrib.auth.views.login'),
            'username': 'super', 'password': 'the_wrong_password')
        self.assertEqual(response.status_code,401)

        # Success redirects to the homepage, so its 302 not 200
        response = self.client.post(reverse('django.contrib.auth.views.login'),
            'username': 'super', 'password': 'the_correct_password')
        self.assertEqual(response.status_code,302)

当我运行测试时,我得到:

(my_app)00:20 ~/my_app (master)$ ./manage.py test my_app.SuperUserTest
Creating test database for alias 'default'...
F
======================================================================
FAIL: test_su_can_login (my_app.SuperUserTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./my_app/tests.py", line 341, in test_su_can_login
    self.assertEqual(response.status_code,401)
AssertionError: 200 != 401

----------------------------------------------------------------------
Ran 1 test in 1.180s

FAILED (failures=1)
Destroying test database for alias 'default'...

为什么 django 在我错误登录时返回 HTTP 代码 200

对于其他上下文,这是我管理登录/注销 url 的方式:

urlpatterns = patterns('',
    # Examples:
    url(r'^accounts/login/?$', 'django.contrib.auth.views.login'),
    url(r'^accounts/logout/?$', 'django.contrib.auth.views.logout',
        'next_page': '/'),

【问题讨论】:

【参考方案1】:

网络社区中存在一些关于对凭据失败的正确响应是什么的争论。例如,这是一个关于从 200 切换到 401 的 Wordpress ticket。在 Stack Overflow 上,您可以找到 some 推荐 200 和 some 推荐 401

Django 选择返回 200 响应以及重新呈现的表单。

在我看来,这是正确的方法。 401403 响应表示用户没有访问资源 (URL) 的权限。但在这种情况下,资源是登录点,您不需要 凭据来访问它;根据定义,它可供所有用户使用。所以本质上,这种情况与任何其他表单验证没有什么不同——服务器正在检查它发送的输入,如果它们无效,它会返回 200 响应以及表单和错误消息。

【讨论】:

【参考方案2】:

我刚刚浏览了 Django 源代码,原因在于 52 行之后的 this 函数。如果表单无效,login 视图返回一个TemplateResponse,只是返回到同一页面并呈现带有错误的表单。

【讨论】:

【参考方案3】:

您可以通过以下方式轻松自定义此行为:

from django.contrib.auth.views import LoginView


class LoginView(LoginView):
    def form_invalid(self, form):
        response = super().form_invalid(form)
        response.status_code = 401
        return response

你需要更改相应的url:

    path("accounts/login/", views.LoginView.as_view(), name="login"),
    path("accounts/", include("django.contrib.auth.urls")),

【讨论】:

你不见了:template_name = 'admin/login.html' 否则说 login.html 不见了。

以上是关于使用错误凭据的 Django 登录返回 200 而不是 401的主要内容,如果未能解决你的问题,请参考以下文章

引导弹出窗口中的 Django 登录表单

ASP.NET Core HttpClient 请求在 webapi 返回 406 时返回 200

Django实现SSO

Django实现SSO

JMeter POST 请求返回 200 OK 而不是 302(重定向)

对于使用错误凭据执行的登录请求,REST API 应返回啥状态代码?