使用错误凭据的 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的主要内容,如果未能解决你的问题,请参考以下文章