El inicio de sesión de Django con credenciales incorrectas devuelve 200 no 401

Esta es una prueba bastante directa, pero parece que no puedo hacerlo bien.

Quiero verificar qué usuarios pueden iniciar sesión y realizar acciones (es parte de un conjunto de pruebas más amplio), pero el primer paso causa algunos problemas.

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) 

Cuando ejecuto la prueba me sale:

 (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'... 

¿Por qué django está devolviendo el código HTTP 200 cuando inicio sesión incorrectamente?

Para un contexto adicional, aquí es cómo administro las direcciones URL de inicio / cierre de sesión:

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

    Existe un debate en la comunidad web sobre cuál es la respuesta correcta ante un error de credenciales. (Por ejemplo, aquí hay un ticket de WordPress sobre el cambio de 200 a 401 ). Django elige devolver una respuesta de 200 junto con el formulario re-renderizado.

    En mi opinión, este es el enfoque correcto. Una respuesta 401 o 403 indica que el usuario no tiene permiso para acceder al recurso (URL). Pero en este caso, el recurso es el punto de inicio de sesión, y no necesita credenciales para acceder a eso; Por definición está disponible para todos los usuarios. Básicamente, este caso no es diferente de cualquier otra validación de formulario: el servidor está verificando las entradas que se enviaron y, si no son válidas, devuelve una respuesta 200 junto con el formulario y un mensaje de error.

    Acabo de echar un vistazo a través del código fuente de Django y la razón por la que está en esta función después de la línea 52 . Si el formulario no es válido, la vista de login devuelve una TemplateResponse , simplemente regresa a la misma página y muestra el formulario con los errores.