Cuando se implementa un nuevo método de autenticación y se llama a una vista con el permiso IsAuthenticated y el usuario no está autenticado, django rest framework genera:
File "XXX/site-packages/rest_framework/views.py", line 206, in check_permissions
self.permission_denied(request)
File "XXX/site-packages/rest_framework/views.py", line 80, in permission_denied
if not self.request.successful_authenticator:
File "XXX/site-packages/rest_framework/request.py", line 362, in __getattr__
return getattr(self._request, attr)
AttributeError: 'WSGIRequest' object has no attribute 'successful_authenticator'
Visto el código, creo que es incorrecto. ¿Dónde está " self.request
.successful_authenticator" creo que debería ser " request
.successful_authenticator".
Views.py, cerca de la línea 80.
def permission_denied(self, request):
"""
If request is not permitted, determine what kind of exception to raise.
"""
if not self.request.successful_authenticator:
raise exceptions.NotAuthenticated()
raise exceptions.PermissionDenied()
Lo siento, cometí los mismos errores en mi código.
Para cualquier otra persona que llegue a este problema a través de Google ...
La pista de la fuente del error es que dice que WSGIRequest
no tiene atributo successful_authenticator
. Pero en este punto del código DRF deberíamos estar tratando con un rest_framework.request.Request
lugar de un WSGIRequest
.
Y, de hecho, si ingresa al código a través de pdb, probablemente encontrará que tiene una solicitud DRF en lugar de un WSGIRequest simple.
El problema es que request.Request
tiene una serie de @property
métodos decorados (como user
, successful_authenticator
y otros) pero también tiene un __getattr__
método.
Lo que sucede es: si el código en cualquiera de las propiedades activa un AttributeError
, Python llamará al método __getattr__
lugar, que finalmente intentará encontrar un atributo (con el mismo nombre que la propiedad que errored) en el objeto secundario WSGIRequest
.
Así es como obtienes errores como 'WSGIRequest' object has no attribute 'successful_authenticator'
o 'WSGIRequest' object has no attribute 'user'
(este último solo si no usas Django AuthenticationMiddleware, por supuesto).
En mi caso, AttributeError provino de uno de mis authentication_classes
... que se llaman a su vez la primera vez que accedes a la propiedad @successful_authenticator
. La combinación de propiedades y __getattr__
en la clase Request enmascara efectivamente la verdadera fuente del error.
Ejecutarlo cuando nuestra vista DRF tenía authentication_classes
incorrectos (accidentalmente, clases de autenticación heredadas para otro marco de api de descanso). Espero que algún día Python se convierta en tipo seguro :)
Para su información, si está utilizando DRF con djangorestframework-expiring-authtoken
< 0.1.4
, verá este error, causado por el siguiente problema:
https://github.com/JamesRitchie/django-rest-framework-expiring-tokens/issues/11
Comentario más útil
Para cualquier otra persona que llegue a este problema a través de Google ...
La pista de la fuente del error es que dice que
WSGIRequest
no tiene atributosuccessful_authenticator
. Pero en este punto del código DRF deberíamos estar tratando con unrest_framework.request.Request
lugar de unWSGIRequest
.Y, de hecho, si ingresa al código a través de pdb, probablemente encontrará que tiene una solicitud DRF en lugar de un WSGIRequest simple.
El problema es que
request.Request
tiene una serie de@property
métodos decorados (comouser
,successful_authenticator
y otros) pero también tiene un__getattr__
método.Lo que sucede es: si el código en cualquiera de las propiedades activa un
AttributeError
, Python llamará al método__getattr__
lugar, que finalmente intentará encontrar un atributo (con el mismo nombre que la propiedad que errored) en el objeto secundarioWSGIRequest
.Así es como obtienes errores como
'WSGIRequest' object has no attribute 'successful_authenticator'
o'WSGIRequest' object has no attribute 'user'
(este último solo si no usas Django AuthenticationMiddleware, por supuesto).En mi caso, AttributeError provino de uno de mis
authentication_classes
... que se llaman a su vez la primera vez que accedes a la propiedad@successful_authenticator
. La combinación de propiedades y__getattr__
en la clase Request enmascara efectivamente la verdadera fuente del error.