Разрешения

Аутентификация или идентификация сами по себе обычно недостаточны для получения доступа к информации или коду. Для этого субъект, запрашивающий доступ, должен иметь авторизацию.

Apple Developer Documentation

Вместе с authentication и :doc:`throttling <throttling>`** , разрешения определяют, должен ли запрос быть удовлетворен или в доступе должно быть отказано.

Проверка разрешений всегда выполняется в самом начале представления, до того, как будет разрешено выполнение любого другого кода. Проверка разрешений обычно использует информацию об аутентификации в свойствах request.user и request.auth, чтобы определить, должен ли быть разрешен входящий запрос.

Разрешения используются для предоставления или запрета доступа различных классов пользователей к различным частям API.

Самый простой стиль разрешения - разрешить доступ любому аутентифицированному пользователю и запретить доступ любому неаутентифицированному пользователю. Это соответствует классу IsAuthenticated в REST framework.

Чуть менее строгий стиль разрешения - разрешить полный доступ для аутентифицированных пользователей, но разрешить доступ только для чтения для неаутентифицированных пользователей. Это соответствует классу IsAuthenticatedOrReadOnly в REST framework.

Как определяются разрешения

Разрешения в REST-фреймворке всегда определяются как список классов разрешений.

Перед запуском основной части представления проверяется каждое разрешение в списке. Если проверка какого-либо разрешения не прошла, будет вызвано исключение exceptions.PermissionDenied или exceptions.NotAuthenticated, и основное тело представления не будет запущено.

При неудачной проверке разрешений возвращается либо ответ «403 Forbidden», либо ответ «401 Unauthorized», в соответствии со следующими правилами:

  • Запрос был успешно аутентифицирован, но в разрешении было отказано. - Будет возвращен ответ HTTP 403 Forbidden.

  • Запрос не был успешно аутентифицирован, а класс аутентификации с наивысшим приоритетом не использует заголовки WWW-Authenticate. - Будет возвращен ответ HTTP 403 Forbidden.

  • Запрос не был успешно аутентифицирован, а класс аутентификации с наивысшим приоритетом должен использовать заголовки WWW-Authenticate. - Будет возвращен ответ HTTP 401 Unauthorized с соответствующим заголовком ``WWW-Authenticate``.

Разрешения на уровне объекта

Разрешения фреймворка REST также поддерживают разрешения на уровне объектов. Разрешения на уровне объекта используются для определения того, разрешено ли пользователю действовать с определенным объектом, который обычно является экземпляром модели.

Разрешения на уровне объектов выполняются общими представлениями REST framework при вызове .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(), описанный в разделе ** *Custom permissions* (ниже).


Ограничения разрешений на уровне объекта

По причинам производительности общие представления не будут автоматически применять разрешения на уровне объекта к каждому экземпляру в наборе запросов при возврате списка объектов.

Часто, когда вы используете разрешения на уровне объекта, вы также хотите filter the queryset соответствующим образом, чтобы гарантировать, что пользователи имеют видимость только тех экземпляров, которые им разрешено просматривать.

Поскольку метод get_object() не вызывается, разрешения объектного уровня из метода has_object_permission() не применяются при создании объектов. Чтобы ограничить создание объектов, вам необходимо реализовать проверку прав либо в классе Serializer, либо переопределить метод 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)

Примечание: когда вы устанавливаете новые классы разрешений с помощью атрибута class или декораторов, вы говорите представлению игнорировать список по умолчанию, установленный в файле 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 model permissions. Это разрешение должно применяться только к представлениям, имеющим .queryset свойство или get_queryset() метод. Разрешение будет предоставлено только в том случае, если пользователь аутентифицирован и имеет соответствующие разрешения модели.

  • Запросы POST требуют, чтобы пользователь имел разрешение add на модель.

  • Запросы PUT и PATCH требуют, чтобы пользователь имел разрешение change на модель.

  • Запросы DELETE требуют, чтобы пользователь имел разрешение delete на модель.

Поведение по умолчанию также можно переопределить для поддержки пользовательских разрешений модели. Например, вы можете включить разрешение модели view для запросов GET.

Чтобы использовать пользовательские разрешения модели, переопределите DjangoModelPermissions и установите свойство .perms_map. Подробности см. в исходном коде.

DjangoModelPermissionsOrAnonReadOnly

Аналогично DjangoModelPermissions , но также позволяет неаутентифицированным пользователям иметь доступ к API только для чтения.

 DjangoObjectPermissions

Этот класс разрешений связан со стандартом Django object permissions framework, который позволяет устанавливать разрешения на модели на уровне объекта. Чтобы использовать этот класс разрешений, вам также необходимо добавить бэкенд разрешений, который поддерживает разрешения на уровне объекта, такие как 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-guardian:doc:` package <https://github.com/rpkilby/django-rest-framework-guardian>`. Он гарантирует, что конечные точки списка возвращают только результаты, включающие объекты, для которых пользователь имеет соответствующие разрешения на просмотр.


Пользовательские разрешения

Чтобы реализовать пользовательское разрешение, переопределите 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, если проверка разрешений на уровне объекта завершится неудачей, а в противном случае просто вернется.

Также обратите внимание, что общие представления будут проверять разрешения на уровне объекта только для представлений, которые получают один экземпляр модели. Если вам требуется фильтрация на уровне объектов для списковых представлений, вам придется фильтровать набор запросов отдельно. Более подробную информацию см. в filtering documentation.

Обзор методов ограничения доступа

Структура REST предлагает три различных метода настройки ограничений доступа в каждом конкретном случае. Они применяются в разных сценариях и имеют различные эффекты и ограничения.

  • queryset /** get_queryset() : Ограничивает общую видимость существующих объектов из базы данных. Кверисет ограничивает, какие объекты будут отображаться в списке и какие объекты могут быть изменены или удалены. Метод get_queryset()> может применять различные кверисеты в зависимости от текущего действия.

  • permission_classes /get_permissions(): Общая проверка прав доступа, основанная на текущем действии, запросе и целевом объекте. Разрешения на уровне объекта могут быть применены только к действиям получения, изменения и удаления. Проверки разрешений для list и create будут применены ко всему типу объекта. (В случае списка: с учетом ограничений в наборе запросов).

  • serializer_class /** get_serializer() : Ограничения на уровне экземпляра, которые применяются ко всем объектам на входе и выходе. Сериализатор может иметь доступ к контексту запроса. Метод get_serializer()> может применять различные сериализаторы в зависимости от текущего действия.

В следующей таблице перечислены методы ограничения доступа и уровень контроля, который они обеспечивают, над какими действиями.


Пакеты сторонних производителей

Также доступны следующие пакеты сторонних производителей.

DRF - Политика доступа

Пакет Django REST - Access Policy предоставляет способ определения сложных правил доступа в декларативных классах политик, которые прикрепляются к наборам представлений или представлениям на основе функций. Политики определяются в JSON в формате, аналогичном политикам AWS Identity & Access Management.

Составленные разрешения

Пакет Composed Permissions предоставляет простой способ определения сложных и многоглубинных (с логическими операторами) объектов разрешения, используя небольшие и многократно используемые компоненты.

Условие REST

Пакет REST Condition - это еще одно расширение для построения сложных разрешений простым и удобным способом. Расширение позволяет комбинировать разрешения с логическими операторами.

DRY Rest Permissions

Пакет DRY Rest Permissions предоставляет возможность определять различные разрешения для отдельных действий по умолчанию и пользовательских действий. Этот пакет предназначен для приложений с разрешениями, которые являются производными от отношений, определенных в модели данных приложения. Он также поддерживает проверку разрешений, возвращаемую клиентскому приложению через сериализатор API. Кроме того, он поддерживает добавление разрешений к действиям списка по умолчанию и пользовательским действиям списка для ограничения данных, которые они извлекают для каждого пользователя.

Роли Django Rest Framework

Пакет Django Rest Framework Roles облегчает параметризацию API для нескольких типов пользователей.

Django REST Framework API Key

Пакет Django REST Framework API Key предоставляет классы разрешений, модели и помощники для добавления авторизации по ключу API в ваш API. Он может быть использован для авторизации внутренних или сторонних бэкендов и сервисов (т.е. машин* ), которые не имеют учетной записи пользователя. API ключи хранятся в безопасном месте с использованием инфраструктуры хэширования паролей Django, и их можно просматривать, редактировать и отзывать в любое время в админке Django.

Ролевые фильтры Django Rest Framework

Пакет Django Rest Framework Role Filters обеспечивает простую фильтрацию по нескольким типам ролей.

Django Rest Framework PSQ

Пакет Django Rest Framework PSQ - это расширение, которое обеспечивает поддержку того, чтобы основанные на действиях классы_разрешений , сериализатор_классов , и queryset зависели от правил, основанных на разрешениях.

Вернуться на верх