Разрешения
Аутентификация или идентификация сами по себе обычно недостаточны для доступа к информации или коду. Для этого у сущности, запрашивающей доступ, должна быть авторизация.
Наряду с аутентификацией и уровнем ограничения запросов, разрешения определяют, должен ли запрос получить доступ или ему будет отказано.
Проверки разрешений всегда выполняются в самом начале представления, прежде чем любая другая часть кода сможет продолжить выполнение. Проверки разрешений обычно используют информацию об аутентификации в свойствах request.user и request.auth, чтобы определить, должен ли разрешаться входящий запрос.
Разрешения используются для предоставления или отказа в доступе для разных категорий пользователей к различным частям API.
Простейший тип разрешений — это разрешение доступа любому аутентифицированному пользователю и отказ в доступе любому неаутентифицированному пользователю. Это соответствует классу IsAuthenticated в REST фреймворке.
Несколько менее строгий стиль разрешений — это предоставление полного доступа аутентифицированным пользователям, но предоставление только чтения неаутентифицированным пользователям. Это соответствует классу IsAuthenticatedOrReadOnly в REST фреймворке.
Как определяются разрешения
Разрешения в REST фреймворке всегда определяются как список классов разрешений.
Перед запуском основной части представления каждая проверка разрешения в списке выполняется. Если любая проверка разрешения завершается неудачно, будет поднято исключение exceptions.PermissionDenied или exceptions.NotAuthenticated, и основная часть представления не будет запущена.
При неудачных проверках разрешений будет возвращён ответ "403 Запрещено" или "401 Не авторизован", согласно следующим правилам:
- Запрос был успешно аутентифицирован, но разрешение было отклонено. — Будет возвращён ответ HTTP 403 Запрещено.
- Запрос не был успешно аутентифицирован, и класс аутентификации с наивысшим приоритетом не использует заголовки
WWW-Authenticate. — Будет возвращён ответ HTTP 403 Запрещено. - Запрос не был успешно аутентифицирован, и класс аутентификации с наивысшим приоритетом использует заголовки
WWW-Authenticate. — Будет возвращён ответ HTTP 401 Не авторизован с соответствующим заголовкомWWW-Authenticate.
Разрешения на уровне объекта
Разрешения REST фреймворка также поддерживают разрешения на уровне объекта. Разрешения на уровне объекта используются для определения, должен ли пользователь иметь право действовать с конкретным объектом, который обычно является экземпляром модели.
Разрешения на уровне объекта выполняются общими представлениями REST фреймворка, когда вызывается .get_object(). Как и в случае с разрешениями на уровне представления, если пользователю не разрешено действовать с данным объектом, будет поднято исключение exceptions.PermissionDenied.
Если вы пишете собственные представления и хотите обеспечить разрешения на уровне объекта, или если вы перезаписываете метод get_object в общем представлении, вам нужно будет явно вызвать метод .check_object_permissions(request, obj) в представлении в тот момент, когда вы получили объект.
Это либо вызовет исключение PermissionDenied или NotAuthenticated, либо просто вернёт значение, если представление имеет соответствующие разрешения.
Например:
def get_object(self):
obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"])
self.check_object_permissions(self.request, obj)
return obj
Примечание: За исключением DjangoObjectPermissions, предоставленные классы разрешений в rest_framework.permissions не реализуют методы, необходимые для проверки разрешений на уровне объекта.
Если вы хотите использовать предоставленные классы разрешений для проверки разрешений на уровне объекта, вы должны унаследовать от них и реализовать метод has_object_permission(), описанный в разделе Настраиваемые разрешения (ниже).
Ограничения разрешений на уровне объекта
По причинам производительности общие представления автоматически не будут применять разрешения на уровне объекта к каждому экземпляру в наборе запросов при возвращении списка объектов.
Часто при использовании разрешений на уровне объекта вам также потребуется фильтровать набор запросов соответствующим образом, чтобы убедиться, что пользователи видят только те экземпляры, которые им разрешено просматривать.
Поскольку метод get_object() не вызывается, разрешения на уровне объекта из метода has_object_permission() не применяются при создании объектов. Для ограничения создания объектов необходимо реализовать проверку разрешений либо в вашем классе сериализатора, либо перезаписать метод perform_create() вашего класса ViewSet.
Установка политики разрешений
Политику разрешений по умолчанию можно установить глобально, используя настройку DEFAULT_PERMISSION_CLASSES. Например.
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
Если не указано, эта настройка по умолчанию разрешает не ограниченный доступ:
'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.AllowAny', ]
Вы также можете установить политику аутентификации на основе представления или на основе набора представлений, используя класс APIView основанных представлений.
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Или, если вы используете декоратор @api_view с функциями основанных представлений.
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Примечание: когда вы устанавливаете новые классы разрешений через атрибут класса или декораторы, вы говорите представлению игнорировать список по умолчанию, заданный в файле settings.py.
При условии, что они унаследованы от rest_framework.permissions.BasePermission, разрешения можно комбинировать, используя стандартные битовые операторы Python. Например, IsAuthenticatedOrReadOnly можно записать:
from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS
from rest_framework.response import Response
from rest_framework.views import APIView
class ReadOnly(BasePermission):
def has_permission(self, request, view):
return request.method in SAFE_METHODS
class ExampleView(APIView):
permission_classes = [IsAuthenticated|ReadOnly]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Примечание: поддерживаются & (и), | (или) и ~ (не).
Справочник по API
AllowAny
Класс разрешений AllowAny разрешит неограниченный доступ, независимо от того, был ли запрос аутентифицирован или нет.
Это разрешение не строго необходимо, поскольку вы можете добиться того же результата, используя пустой список или кортеж для настройки разрешений, но вы можете найти его полезным, потому что он делает намерение явным.
IsAuthenticated
Класс разрешений IsAuthenticated откажет в разрешении любому неаутентифицированному пользователю и разрешит в противном случае.
Это разрешение подходит, если вы хотите, чтобы ваш API был доступен только зарегистрированным пользователям.
IsAdminUser
Класс разрешений IsAdminUser откажет в разрешении любому пользователю, если user.is_staff является True, в этом случае разрешение будет предоставлено.
Это разрешение подходит, если вы хотите, чтобы ваш API был доступен только подмножеству доверенных администраторов.
IsAuthenticatedOrReadOnly
IsAuthenticatedOrReadOnly разрешит аутентифицированным пользователям выполнять любые запросы. Запросы от неаутентифицированных пользователей будут разрешены только в том случае, если метод запроса является одним из «безопасных» методов; GET, HEAD или OPTIONS.
Это разрешение подходит, если вы хотите, чтобы ваш API разрешал права чтения анонимным пользователям и разрешал только права записи аутентифицированным пользователям.
DjangoModelPermissions
Этот класс разрешений связан со стандартными разрешениями на модели Django django.contrib.auth разрешения на модели. Это разрешение должно применяться только к представлениям, которые имеют свойство .queryset или метод get_queryset(). Авторизация будет предоставлена только в том случае, если пользователь аутентифицирован и имеет назначенные соответствующие разрешения на модель. Соответствующая модель определяется путем проверки get_queryset().model или queryset.model.
-
POSTзапросы требуют, чтобы у пользователя было разрешениеaddна модели. -
PUTиPATCHзапросы требуют, чтобы у пользователя было разрешениеchangeна модели. -
DELETEзапросы требуют, чтобы у пользователя было разрешениеdeleteна модели.
Поведение по умолчанию также можно изменить для поддержки настраиваемых разрешений на модели. Например, вы можете добавить разрешение на модель view для GET запросов.
Для использования настраиваемых разрешений на модели переопределите DjangoModelPermissions и задайте свойство .perms_map. Обратитесь к исходному коду для получения подробностей.
DjangoModelPermissionsOrAnonReadOnly
Аналогично DjangoModelPermissions, но также разрешает неаутентифицированным пользователям иметь только права чтения к API.
DjangoObjectPermissions
Этот класс разрешений связан со стандартной системой разрешений на объекты Django, которая позволяет разрешения на уровне объектов для моделей. Для использования этого класса разрешений вам также необходимо добавить бэкенд разрешений, поддерживающий разрешения на уровне объектов, например, django-guardian.
Как и DjangoModelPermissions, это разрешение должно применяться только к представлениям, которые имеют свойство .queryset или метод .get_queryset(). Авторизация будет предоставлена только в том случае, если пользователь аутентифицирован и имеет соответствующие разрешения на объект и соответствующие разрешения на модель.
-
POSTзапросы требуют, чтобы у пользователя было разрешениеaddна экземпляре модели. -
PUTиPATCHзапросы требуют, чтобы у пользователя было разрешениеchangeна экземпляре модели. -
DELETEзапросы требуют, чтобы у пользователя было разрешениеdeleteна экземпляре модели.
Обратите внимание, что DjangoObjectPermissions не требует пакета django-guardian и должен поддерживать другие бэкенды на уровне объектов так же хорошо.
Как и DjangoModelPermissions, вы можете использовать настраиваемые разрешения на модели, переопределив DjangoObjectPermissions и задав свойство .perms_map. Обратитесь к исходному коду для получения подробностей.
Примечание: Если вам нужны разрешения на уровне объекта view для GET, HEAD и OPTIONS запросов и вы используете django-guardian для вашего бэкенда разрешений на уровне объектов, вам следует рассмотреть использование класса DjangoObjectPermissionsFilter из пакета djangorestframework-guardian2. Он гарантирует, что в результатах списка отображаются только объекты, для которых у пользователя есть соответствующие разрешения на просмотр.
Настраиваемые разрешения
Для реализации настраиваемого разрешения переопределите BasePermission и реализуйте любой или оба из следующих методов:
.has_permission(self, request, view).has_object_permission(self, request, view, obj)
Методы должны возвращать True , если запросу следует предоставить доступ, и False в противном случае.
Если вам нужно проверить, является ли запрос операцией чтения или записи, вы должны сравнить метод запроса с константой SAFE_METHODS, которая представляет собой кортеж, содержащий 'GET', 'OPTIONS' и 'HEAD'. Например:
if request.method in permissions.SAFE_METHODS:
# Check permissions for read-only request
else:
# Check permissions for write request
Примечание: метод уровня экземпляра has_object_permission будет вызван только в том случае, если проверки на уровне представления has_permission уже пройдены. Также обратите внимание, что для запуска проверок на уровне экземпляра код представления должен явно вызвать .check_object_permissions(request, obj). Если вы используете обобщенные представления, это будет обрабатываться по умолчанию. (Для представлений на основе функций необходимо явно проверить разрешения объекта, выбросив исключение PermissionDenied при ошибке.)
Пользовательские разрешения вызовут исключение PermissionDenied , если проверка завершится неудачно. Чтобы изменить сообщение об ошибке, связанное с исключением, реализуйте атрибут message непосредственно в пользовательском разрешении. В противном случае будет использоваться атрибут default_detail из PermissionDenied. Аналогично, чтобы изменить идентификатор кода, связанный с исключением, реализуйте атрибут code непосредственно в пользовательском разрешении; в противном случае будет использоваться атрибут default_code из PermissionDenied.
from rest_framework import permissions
class CustomerAccessPermission(permissions.BasePermission):
message = 'Adding customers not allowed.'
def has_permission(self, request, view):
...
Примеры
Ниже приведен пример класса разрешений, который проверяет IP-адрес входящего запроса на наличие в списке блокировок и отклоняет запрос, если IP-адрес заблокирован.
from rest_framework import permissions
class BlocklistPermission(permissions.BasePermission):
"""
Global permission check for blocked IPs.
"""
def has_permission(self, request, view):
ip_addr = request.META['REMOTE_ADDR']
blocked = Blocklist.objects.filter(ip_addr=ip_addr).exists()
return not blocked
Помимо глобальных разрешений, которые применяются ко всем входящим запросам, вы также можете создавать разрешения на уровне объекта, которые применяются только к операциям, влияющим на определенный экземпляр объекта. Например:
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Instance must have an attribute named `owner`.
return obj.owner == request.user
Обратите внимание, что обобщенные представления будут проверять соответствующие разрешения на уровне объекта, но если вы пишете собственные пользовательские представления, вам нужно убедиться, что вы проверяете проверки разрешений на уровне объекта самостоятельно. Вы можете сделать это, вызвав self.check_object_permissions(request, obj) из представления после получения экземпляра объекта. Этот вызов выбросит соответствующее исключение APIException , если какие-либо проверки разрешений на уровне объекта завершатся неудачно, в противном случае просто вернёт значение.
Также обратите внимание, что обобщенные представления будут проверять только разрешения на уровне объекта для представлений, которые извлекают один экземпляр модели. Если вам необходима фильтрация на уровне объекта для представлений списков, вам нужно отфильтровать набор запросов отдельно. Дополнительные сведения см. в документации по фильтрации.
Обзор методов ограничения доступа
REST framework предлагает три различных метода для настройки ограничений доступа на индивидуальной основе. Они применяются в разных сценариях и имеют разные эффекты и ограничения.
-
queryset/get_queryset(): Ограничивает общую видимость существующих объектов из базы данных. Набор запросов ограничивает, какие объекты будут отображаться, и какие объекты можно изменять или удалять. Методget_queryset()может применять различные наборы запросов в зависимости от текущего действия. -
permission_classes/get_permissions(): Общие проверки разрешений, основанные на текущем действии, запросе и целевом объекте. Разрешения на уровне объекта могут применяться только к операциям извлечения, изменения и удаления. Проверки разрешений для действий списка и создания будут применяться ко всему типу объекта. (В случае списка: подлежат ограничениям в наборе запросов.) -
serializer_class/get_serializer(): Ограничения на уровне экземпляра, которые применяются ко всем объектам на входе и выходе. Сериализатор может иметь доступ к контексту запроса. Методget_serializer()может применять различные сериализаторы в зависимости от текущего действия.
В следующей таблице перечислены методы ограничения доступа и уровень управления, который они предоставляют над действиями.
queryset | permission_classes | serializer_class | |
|---|---|---|---|
| Действие: список | глобальный | глобальный | уровень объекта* |
| Действие: создание | нет | глобальный | уровень объекта |
| Действие: извлечение | глобальный | уровень объекта | уровень объекта |
| Действие: обновление | глобальный | уровень объекта | уровень объекта |
| Действие: частичное обновление | глобальный | уровень объекта | уровень объекта |
| Действие: удаление | глобальный | уровень объекта | нет |
| Может ссылаться на действие в принятии решения | нет** | да | нет** |
| Может ссылаться на запрос в принятии решения | нет** | да | да |
* Класс сериализатора не должен вызывать PermissionDenied в действии списка, иначе весь список не будет возвращен.
** Методы get_*() имеют доступ к текущему представлению и могут возвращать различные экземпляры сериализатора или набора запросов в зависимости от запроса или действия.
Пакеты сторонних разработчиков
Доступны следующие пакеты сторонних разработчиков.
DRF - Политика доступа
Пакет Django REST - Политика доступа предоставляет способ определения сложных правил доступа в декларативных классах политики, которые прикреплены к наборам представлений или представлениям на основе функций. Политики определены в формате JSON, аналогичном политикам управления идентификацией и доступом AWS.
Составные разрешения
Пакет Составные разрешения предоставляет простой способ определения сложных и многоуровневых (с логическими операторами) объектов разрешений, используя небольшие и многоразовые компоненты.
REST-условие
Пакет REST-условие — это еще одно расширение для создания сложных разрешений простым и удобным способом. Расширение позволяет комбинировать разрешения с логическими операторами.
Сухие разрешения REST
Пакет Сухие разрешения REST предоставляет возможность определить разные разрешения для отдельных стандартных и пользовательских действий. Этот пакет предназначен для приложений с разрешениями, которые выводятся из отношений, определенных в модели данных приложения. Он также поддерживает возвращение проверок разрешений в приложение-клиент через сериализатор API. Кроме того, он поддерживает добавление разрешений к стандартным и пользовательским действиям списка для ограничения данных, которые они извлекают для каждого пользователя.
Django Rest Framework Роли
Пакет Django Rest Framework Роли упрощает параметризацию API для нескольких типов пользователей.
Rest Framework Роли
Пакет Rest Framework Роли делает защиту представлений на основе ролей очень простой. Что наиболее важно, он позволяет отделить логику доступа от моделей и представлений понятным человеческим языком.
Django REST Framework Ключ API
Пакет Django REST Framework Ключ API предоставляет классы разрешений, модели и вспомогательные функции для добавления авторизации ключа API в ваш API. Он может использоваться для авторизации внутренних или сторонних бэкендов и служб (например, машин), не имеющих учетной записи пользователя. Ключи API хранятся безопасно с использованием инфраструктуры хеширования паролей Django, и их можно просматривать, редактировать и отзывать в любой момент в админке Django.
Django Rest Framework Фильтры ролей
Пакет Django Rest Framework Фильтры ролей предоставляет простую фильтрацию по нескольким типам ролей.
Django Rest Framework PSQ
Пакет Django Rest Framework PSQ — это расширение, которое поддерживает использование permission_classes, serializer_class и queryset, зависящих от правил разрешений, на основе действий.
Copyright © 2011–present Encode OSS Ltd.
Licensed under the BSD License.
https://www.django-rest-framework.org/api-guide/permissions/