Почему встроенные классы разрешений Django REST Framework имеют проверку request.user?
Я пишу свой первый проект DRF, и меня заинтересовало, как реализованы встроенные классы разрешений DRF - IsAuthenticated
и IsAdminUser
, например.
В rest_framework/permissions.py
вы можете найти следующий код:
class IsAdminUser(BasePermission):
...
def has_permission(self, request, view):
return bool(request.user and request.user.is_staff)
class IsAuthenticated(BasePermission):
...
def has_permission(self, request, view):
return bool(request.user and request.user.is_authenticated)
Как видите, оба класса проверяют наличие request.user
перед вторым условием.
Возможно, это необходимо по какой-то причине, но я не могу понять, почему.
Первое, что пришло мне в голову, это то, что объект request.user
может иметь значение None
или иметь какой-то объект без атрибутов is_staff
или is_authenticated
, и в этом случае request.user.is_staff
и request.user.is_authenticated
вызовут AttributeError
.
Я немного поэкспериментировал, и даже если я посылаю неаутентифицированный запрос, request.user
указывает на AnonymousUser
. То же самое написано в документации:
Если ни один класс не аутентифицируется, request.user будет установлен в экземпляр django.contrib.auth.models.AnonymousUser, а request.auth будет установлен на None.
Но самое интересное здесь то, что AnonymousUser
объект
на самом деле имеет атрибуты is_staff
и is_authenticated
! Оба они установлены в
False
.
Так почему же вы сначала проверяете наличие request.user
, а не проверяете напрямую условия request.user.is_staff
и request.user.is_authenticated
?
request.user
- это способ запустить всю логику аутентификации в django-rest-framework. Это ленивое свойство, доступ к которому должен быть получен до появления таких атрибутов, как request.user.is_authenticated
.
Релевантный код в django-rest-framework:
class Request:
…
@property
def user(self):
"""
Returns the user associated with the current request, as authenticated
by the authentication classes provided to the request.
"""
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
Как видите, доступ к свойству запускает всю логику аутентификации, которая необходима для работы следующей проверки разрешений.