Авторизация (проверка прав)

При действующем уровне доступа к вашему API любой аутентифицированный пользователь может удалять и редактировать не только свои, но и чужие записи. Это неправильно.
В курсе Django вы применяли декоратор @login_required для ограничения доступа к определённым страницам проекта. В прошлом спринте вы узнали, как ограничить доступ к API для неаутентифициронных пользователей. Но и этого недостаточно.
Безопасность — важная часть любого сервиса, и если вы не настроите механизмы авторизации, любой пользователь получит полный доступ ко всем функциям API.
Самое время разобраться со встроенными разрешениями и настроить права доступа так, чтобы редактировать и удалять записи могли только их авторы.

Разрешения (Permissions)

При запросе к API одновременно с аутентификацией система определяет, достаточно ли прав у пользователя на выполнение запрошенных операций. Эта проверка выполняется в самом начале обработки запроса.
Настроить права доступа (или «пермишены», в таком виде этот термин тоже будет вам встречаться) можно на уровне всего проекта, на уровне отдельного приложения или даже на уровне отдельных классов.
Начнём с уровня проекта: будет надёжнее установить глобальные ограничения, а потом ослабить их там, где это необходимо.
Для установки ограничений на уровне проекта в словаре настроек REST_FRAMEWORK задайте параметр DEFAULT_PERMISSION_CLASSES
settings.py
Скопировать кодPYTHON
REST_FRAMEWORK = { ... 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ], }
На уровне проекта можно установить один из четырёх вариантов доступа:
  • AllowAny — всё разрешено, любой пользователь (и даже аноним) может выполнить любой запрос.
  • IsAuthenticated — только аутентифицированные (зарегистрированные) пользователи имеют доступ к API и могут выполнить любой запрос.
  • IsAuthenticatedOrReadOnly — неаутентифицированные пользователи могут совершать запросы на чтение, но не могут ничего создавать, удалять или изменять.
  • IsAdminUser — только администраторы/суперпользователи могут делать запросы.
Чтобы настроить разрешения на уровне view-класса, импортируйте модуль permissions из пакета rest_framework и добавьте поле permission_classes в тело класса:
Скопировать кодPYTHON
class PostViewSet(viewsets.ModelViewSet): queryset = Post.objects.all() serializer_class = PostSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

Создание собственных разрешений

Иногда возникает необходимость в написании собственных разрешений. Например, вы хотите, чтобы редактировать или удалять пост мог только администратор или автор, а всем прочим пользователям пост должен быть доступен только для чтения.
В Django REST Framework есть базовый класс BasePermission, от него наследуются все классы разрешений. Его методы принимают на вход:
  • объект запроса request: содержит все данные запроса
  • объект view: объект (класс или функция), к этому объекту можно обратиться, чтобы проверить какие-то поля или методы
  • объект obj: объект, права на доступ к которому проверяются
Этот класс применяют для ограничения доступа на уровне объектов. Доступ будет разрешён, если метод BasePermission вернёт True.
Скопировать кодPYTHON
class BasePermission(metaclass=BasePermissionMetaclass): """ A base class from which all permission classes should inherit. """ def has_permission(self, request, view): """ Return `True` if permission is granted, `False` otherwise. """ return True def has_object_permission(self, request, view, obj): """ Return `True` if permission is granted, `False` otherwise. """ return True
Чтобы создать собственное разрешение — опишите свой класс, расширяющий BasePermission и переопределите один из его методов.
Пример класса, который позволяет любые действия администратору, а больше никому:
Скопировать кодPYTHON
class IsSuperuserPermission(permissions.BasePermission): def has_permission(self, request, view): return request.user.is_superuser
Чтобы применить ограничения к view-классу, импортируйте IsSuperuserPermission во views.py и добавьте поле permission_classes во view-функцию:
Скопировать кодPYTHON
from .permissions import IsSuperuserPermission class PostViewSet(viewsets.ModelViewSet): queryset = Post.objects.all() serializer_class = PostSerializer permission_classes = (IsSuperuserPermission,)
Встроенный в Django метод .is_superuser вернёт True, если пользователь из request.user — администратор.
Если метод вернёт False, запрос не будет обработан и вернётся такое сообщение:
Скопировать кодJSON
{ "detail": "You do not have permission to perform this action." }