Перевод: Špela Giacomelli (aka GirlLovesToCode) — Permissions in Django Rest Framework
В этой статье рассматриваются особенности использования разрешений has_permission и has_object_permission в Django REST Framework (DRF).
К концу этой статьи вы сможете объяснить:
В DRF разрешения, наряду с аутентификацией (authentication) и регулированием (throttling), используются для предоставления или отказа в доступе для разных классов пользователей к разным частям API.
Аутентификация и авторизация работают рука об руку. Аутентификация всегда выполняется перед авторизацией.
В то время как аутентификация — это процесс проверки личности пользователя (пользователя, от которого поступил запрос, токена, которым он был подписан), авторизация — это процесс проверки того, имеет ли пользователь необходимые разрешения для выполнения запроса (является ли он супер пользователем, или является создателем объекта).
Процесс авторизации в DRF регулируется разрешениями.
APIView имеет два метода проверки разрешений:
check_permissions
проверяет, следует ли разрешить запрос на основе данных запросаcheck_object_permissions
проверяет, следует ли разрешить запрос на основе комбинации данных запроса и объекта# rest_framework/views.py class APIView(View): # other methods def check_permissions(self, request): """ Check if the request should be permitted. Raises an appropriate exception if the request is not permitted. """ for permission in self.get_permissions(): if not permission.has_permission(request, self): self.permission_denied( request, message=getattr(permission, 'message', None), code=getattr(permission, 'code', None) ) def check_object_permissions(self, request, obj): """ Check if the request should be permitted for a given object. Raises an appropriate exception if the request is not permitted. """ for permission in self.get_permissions(): if not permission.has_object_permission(request, self, obj): self.permission_denied( request, message=getattr(permission, 'message', None), code=getattr(permission, 'code', None) )
При поступлении запроса выполняется аутентификация. Если аутентификация не удалась, возникает ошибка NotAuthenticated. После этого все разрешения проверяются в цикле, и в случае сбоя какого-либо из них возникает ошибка PermissionDenied. Далее, для запроса выполняется проверка throttling.
check_permissions вызывается перед выполнением обработчика представления, в то время как check_object_permissions не выполняется, если вы явно не вызываете его. Например таким образом:
class MessageSingleAPI(APIView): def get(self, request, pk): message = get_object_or_404(Message.objects.all(), pk=pk) self.check_object_permissions(request, message) # explicitly called serializer = MessageSerializer(message) return Response(serializer.data)
С ViewSets и Generic Views, check_object_permissions вызывается после извлечения объекта из базы данных для всех подробных представлений (detail views).
# rest_framework/generics.py class GenericAPIView(views.APIView): # other methods def get_object(self): """ Returns the object the view is displaying. You may want to override this if you need to provide non-standard queryset lookups. Eg if objects are referenced using multiple keyword arguments in the url conf. """ queryset = self.filter_queryset(self.get_queryset()) # Perform the lookup filtering. lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field assert lookup_url_kwarg in self.kwargs, ( 'Expected view %s to be called with a URL keyword argument ' 'named "%s". Fix your URL conf, or set the `.lookup_field` ' 'attribute on the view correctly.' % (self.__class__.__name__, lookup_url_kwarg) ) filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]} obj = get_object_or_404(queryset, **filter_kwargs) # May raise a permission denied self.check_object_permissions(self.request, obj) # HERE return obj
Права проверяется для всех разрешений, и если одно из них возвращает False, возникает ошибка PermissionDenied.
Разрешения в DRF определяются как список классов разрешений. Вы можете создать свой собственный класс или использовать один из семи встроенных классов. Все классы разрешений, настраиваемые или встроенные, являются наследниками класса BasePermission:
class BasePermission(metaclass=BasePermissionMetaclass): def has_permission(self, request, view): return True def has_object_permission(self, request, view, obj): return True
Как видите, BasePermission имеет два метода, has_permission и has_object_permission, оба из которых возвращают True. Классы разрешений переопределяют один или оба метода для изменения возвращаемого значения.
Вернемся к методам check_permissions и check_object_permissions из начала статьи:
check_permissions
вызывает has_permission для каждого из разрешенийcheck_object_permissions
также вызывает has_object_permission для каждого из разрешенийhas_permission
используется, чтобы решить, разрешен ли запрос и имеет ли пользователь доступ к определенному представлению
Например:
has_permission
обладает информацией о запросе, но не об объекте запроса.
Как объяснялось в начале, has_permission (вызываемый check_permissions) выполняется до выполнения обработчика представления (view), без явного его вызова.
has_object_permission используется, чтобы решить, разрешено ли конкретному пользователю взаимодействовать с определенным объектом.
Например:
Помимо информации о запросе, has_object_permission также обладает данными об объекте запроса. Метод выполняется после получения объекта из базы данных.
В отличие от has_permission, has_object_permission не всегда выполняется по умолчанию:
В чем разница между has_permission и has_object_permission в Django REST Framework?
Опять же, для:
Что касается встроенных классов разрешений DRF, все они переопределяют has_permission, в то время как только DjangoObjectPermissions переопределяет has_object_permission:
Permission class | has_permission | has_object_permission |
---|---|---|
AllowAny | ✓ | ✗ |
IsAuthenticated | ✓ | ✗ |
IsAdminUser | ✓ | ✗ |
IsAuthenticatedOrReadOnly | ✓ | ✗ |
DjangoModelPermissions | ✓ | ✗ |
DjangoModelPermissionsOrAnonReadOnly | ✓ | ✗ |
DjangoObjectPermissions | by extending DjangoModelPermissions | ✓ |
Для пользовательских классов разрешений (custom permission classes) вы можете переопределить один или оба метода. Если вы переопределяете только одно из них, вам нужно быть осторожным, особенно если используемые вами разрешения сложны или вы объединяете несколько разрешений. Оба параметра has_permission и has_object_permission по умолчанию имеют значение True, поэтому, если вы не укажете одно из них явно, отклонение запроса будет зависеть от того, который вы явно установили.
Давайте посмотрим на простой пример:
from rest_framework import permissions class AuthorOrReadOnly(permissions.BasePermission): def has_permission(self, request, view): if request.user.is_authenticated: return True return False def has_object_permission(self, request, view, obj): if obj.author == request.user: return True return False
Этот класс разрешений разрешает доступ к нему только автору объекта:
Полученные результаты:
List view | Detail view | |
---|---|---|
has_permission | Предоставляет разрешение аутентифицированному пользователю | Предоставляет разрешение аутентифицированному пользователю |
has_object_permission | Не влияет | Предоставляет разрешение автору объекта |
Result | Доступ предоставлен аутентифицированным пользователям | Доступ предоставляется владельцу объекта, если он аутентифицирован |
Давайте посмотрим на разрешение, которое лучше не делать, мы его создали только для того чтобы лучше понять, что происходит:
from rest_framework import permissions class AuthenticatedOnly(permissions.BasePermission): def has_object_permission(self, request, view, obj): if request.user.is_authenticated: return True return False
Это разрешение запрещает доступ неаутентифицированному пользователю, но проверка выполняется в has_object_permission вместо has_permission.
Что тут происходит?
Вот почему в этом примере неаутентифицированные запросы не имеют доступа к подробным представлениям, но у них есть доступ к представлениям списков.
List view | Detail view | |
---|---|---|
has_permission | Использует функцию по умолчанию, которая предоставляет разрешение без каких-либо условий | Использует функцию по умолчанию, которая предоставляет разрешение без каких-либо условий |
has_object_permission | Не влияет | Предоставляет разрешение аутентифицированному пользователю |
Result | Разрешение всегда предоставляется | Разрешение предоставляется авторизованным пользователям |
Этот класс разрешений был создан только для того, чтобы показать, как работают два метода. Вам следует использовать встроенный класс IsAuthenticated вместо того, чтобы создавать свой собственный.
Все разрешения, настраиваемые или встроенные, в Django REST Framework используют метод либо has_permission, либо has_object_permission, либо оба варианта для ограничения доступа к конечным точкам API.
Хотя has_permission не имеет ограничений относительно того, когда его можно использовать, у него нет доступа к желаемому объекту. Из-за этого это скорее «общая» проверка разрешений, чтобы гарантировать, что запрос и пользователь могут получить доступ к представлению. С другой стороны, поскольку has_object_permission имеет доступ к объекту, разрешения которого могут быть гораздо более конкретными, но у него есть много ограничений относительно того, когда его можно использовать.
Имейте в виду, что если вы не переопределите методы, они всегда будут возвращать True, предоставляя неограниченный доступ. При этом has_permission влияет только на доступ к представлениям списков, в то время как они оба влияют на доступ к подробному представлению.
Знание и понимание того, как работают оба этих метода, особенно важно при создании пользовательских (custom) классов разрешений.
Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…
Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…
Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…
Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…
Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…
Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…
View Comments
Пожалуй, не разрешения а права