JavaRush /Курсы /Модуль 3: Django /Разрешения (Permissions) в Django REST Framework

Разрешения (Permissions) в Django REST Framework

Модуль 3: Django
18 уровень , 7 лекция
Открыта

Сегодня мы перейдём к следующему важному аспекту безопасности в DRF — разрешениям (permissions). Они определяют, кто имеет доступ к определённым ресурсам, и обеспечивают гибкость в настройке доступа на уровне представлений (views). Погнали!

Что такое разрешения в DRF?

Разрешения — это механизмы управления доступом к вашим API. Они позволяют определить, какие пользователи (или группы пользователей) могут взаимодействовать с вашими ресурсами. Например, вы можете предоставить доступ к чтению данных всем, но разрешить изменения только администраторам.

Если аутентификация отвечает на вопрос "Кто это?", то разрешения отвечают на вопрос "А что им можно делать?". В DRF разрешения применяются на уровне представлений (views) или ViewSet.

Представьте библиотеку API, где:

  • Анонимные пользователи могут искать книги.
  • Авторизованные пользователи могут создавать свои списки чтения.
  • Только администраторы могут добавлять новые книги в базу данных.

Разрешения помогают настроить такие правила!

Встроенные классы разрешений

Django REST Framework предоставляет несколько стандартных классов разрешений. Давайте разберёмся, как они работают.

  1. AllowAny

Это разрешение позволяет доступ к ресурсу вообще всем! Оно полезно, например, для страниц регистрации, входа в систему или публичных API.

from rest_framework.permissions import AllowAny

class PublicView(APIView):
    permission_classes = [AllowAny]

    def get(self, request):
        return Response({"message": "Этот ресурс доступен всем!"})
  1. IsAuthenticated

Это разрешение требует, чтобы пользователь был аутентифицирован. Если пользователь не вошёл в систему, ему покажут ошибку 401 Unauthorized.

from rest_framework.permissions import IsAuthenticated

class PrivateView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        return Response({"message": f"Привет, {request.user.username}!"})
  1. IsAdminUser

Только пользователи с правами администратора (атрибут is_staff=True у модели User) имеют доступ.

from rest_framework.permissions import IsAdminUser

class AdminView(APIView):
    permission_classes = [IsAdminUser]

    def post(self, request):
        return Response({"message": "Доступ разрешён только администраторам!"})
  1. IsAuthenticatedOrReadOnly

Пользователи могут читать данные (GET-запросы) без авторизации, но для изменения POST, PUT, DELETE требуется быть аутентифицированным.

from rest_framework.permissions import IsAuthenticatedOrReadOnly

class BookView(APIView):
    permission_classes = [IsAuthenticatedOrReadOnly]

    def get(self, request):
        return Response({"books": ["Book 1", "Book 2"]})

    def post(self, request):
        return Response({"message": "Вы добавили новую книгу!"})

Применение разрешений

Разрешения задаются в представлениях (views) или ViewSet с использованием атрибута permission_classes. Давайте посмотрим на примеры для обоих подходов.

Применение в представлениях (APIView)

from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated

class ExampleView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        return Response({"message": "Только для авторизованных пользователей"})

Применение в ViewSet

from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAdminUser
from .models import Book
from .serializers import BookSerializer

class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = [IsAdminUser]
Примечание:

при работе с ViewSet, применённые разрешения будут относиться ко всем действиям (list, retrieve, create и т.д.).

Комбинирование разрешений

В DRF есть возможность комбинировать несколько разрешений. Если хотя бы одно из разрешений запрещает доступ, пользователь получит ответ с ошибкой 403 Forbidden.

Пример комбинирования

from rest_framework.permissions import IsAuthenticated, IsAdminUser

class CombinedView(APIView):
    permission_classes = [IsAuthenticated, IsAdminUser]

    def get(self, request):
        return Response({"message": "Вы должны быть авторизованным администратором!"})

В этом примере только авторизованные администраторы смогут получить доступ. Если пользователь не аутентифицирован или он не администратор, доступ будет закрыт.

Кастомные разрешения

Иногда стандартных разрешений недостаточно. К счастью, DRF позволяет создавать свои классы разрешений. Это может быть полезно в сложных сценариях, например, если доступ зависит от свойств объекта.

Кастомное разрешение должно быть классом, который наследует BasePermission и реализует метод has_permission() или has_object_permission() (или оба).

Давайте напишем пример с разрешением для владельцев данных

from rest_framework.permissions import BasePermission

class IsOwner(BasePermission):
    def has_object_permission(self, request, view, obj):
        # Доступ только если пользователь — владелец объекта
        return obj.owner == request.user

Использование кастомного разрешения

from rest_framework.views import APIView
from .permissions import IsOwner

class OwnerOnlyView(APIView):
    permission_classes = [IsAuthenticated, IsOwner]

    def get_object(self):
        # Получаем объект (например, через QuerySet)
        return MyModel.objects.get(pk=self.kwargs['pk'])

    def get(self, request, pk):
        obj = self.get_object()
        self.check_object_permissions(request, obj)
        return Response({"message": "Вы владелец объекта!"})

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

Разрешения уровня объекта позволяют проверять доступ к конкретному объекту. Метод has_object_permission() вызывается, когда вы хотите убедиться, что пользователь имеет право взаимодействовать с этим объектом.

Пример: доступ к объекту, если пользователь администратор или владелец

from rest_framework.permissions import BasePermission

class IsAdminOrOwner(BasePermission):
    def has_object_permission(self, request, view, obj):
        return request.user.is_staff or obj.owner == request.user

Типичные ошибки и особенности

  1. Ошибка "Permission denied"

    • Если ваше представление использует разрешение, а вы не настроили механизм аутентификации, DRF выдаст ошибку. Убедитесь, что в settings.py указан DEFAULT_AUTHENTICATION_CLASSES.
  2. Разрешение на уровне объекта

    • Методы уровня объекта has_object_permission не вызываются для списков (list). Если нужно применить логику, фильтруйте QuerySet в методе get_queryset().
  3. Забыли про check_object_permissions()

    • Если вы используете объектные разрешения, не забудьте вручную вызвать check_object_permissions.

Практическое упражнение

Как создать разрешения для блога? Нужно проделать следующие шаги:

  1. Создайте модели Post и Comment. У каждой записи Post должно быть поле author.
  2. Настройте разрешение, позволяющее только владельцу поста его редактировать.
  3. Настройте разрешение, позволяющее только аутентифицированным пользователям добавлять комментарии.
  4. Анонимные пользователи могут читать посты, но не комментировать.

Теперь вы понимаете, как настраивать и кастомизировать разрешения в DRF. Использование этих механизмов позволяет строить безопасные и гибкие API.

1
Задача
Модуль 3: Django, 18 уровень, 7 лекция
Недоступна
Применение встроенных разрешений
Применение встроенных разрешений
1
Задача
Модуль 3: Django, 18 уровень, 7 лекция
Недоступна
Кастомное разрешение для проверки возраста
Кастомное разрешение для проверки возраста
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ