Сегодня мы перейдём к следующему важному аспекту безопасности в DRF — разрешениям (permissions). Они определяют, кто имеет доступ к определённым ресурсам, и обеспечивают гибкость в настройке доступа на уровне представлений (views). Погнали!
Что такое разрешения в DRF?
Разрешения — это механизмы управления доступом к вашим API. Они позволяют определить, какие пользователи (или группы пользователей) могут взаимодействовать с вашими ресурсами. Например, вы можете предоставить доступ к чтению данных всем, но разрешить изменения только администраторам.
Если аутентификация отвечает на вопрос "Кто это?", то разрешения отвечают на вопрос "А что им можно делать?". В DRF разрешения применяются на уровне представлений (views) или ViewSet.
Представьте библиотеку API, где:
- Анонимные пользователи могут искать книги.
- Авторизованные пользователи могут создавать свои списки чтения.
- Только администраторы могут добавлять новые книги в базу данных.
Разрешения помогают настроить такие правила!
Встроенные классы разрешений
Django REST Framework предоставляет несколько стандартных классов разрешений. Давайте разберёмся, как они работают.
AllowAny
Это разрешение позволяет доступ к ресурсу вообще всем! Оно полезно, например, для страниц регистрации, входа в систему или публичных API.
from rest_framework.permissions import AllowAny
class PublicView(APIView):
permission_classes = [AllowAny]
def get(self, request):
return Response({"message": "Этот ресурс доступен всем!"})
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}!"})
IsAdminUser
Только пользователи с правами администратора (атрибут is_staff=True у модели User) имеют доступ.
from rest_framework.permissions import IsAdminUser
class AdminView(APIView):
permission_classes = [IsAdminUser]
def post(self, request):
return Response({"message": "Доступ разрешён только администраторам!"})
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
Типичные ошибки и особенности
Ошибка "Permission denied"
- Если ваше представление использует разрешение, а вы не настроили механизм аутентификации, DRF выдаст ошибку. Убедитесь, что в
settings.pyуказанDEFAULT_AUTHENTICATION_CLASSES.
- Если ваше представление использует разрешение, а вы не настроили механизм аутентификации, DRF выдаст ошибку. Убедитесь, что в
Разрешение на уровне объекта
- Методы уровня объекта
has_object_permissionне вызываются для списков (list). Если нужно применить логику, фильтруйте QuerySet в методеget_queryset().
- Методы уровня объекта
Забыли про
check_object_permissions()- Если вы используете объектные разрешения, не забудьте вручную вызвать
check_object_permissions.
- Если вы используете объектные разрешения, не забудьте вручную вызвать
Практическое упражнение
Как создать разрешения для блога? Нужно проделать следующие шаги:
- Создайте модели
PostиComment. У каждой записиPostдолжно быть полеauthor. - Настройте разрешение, позволяющее только владельцу поста его редактировать.
- Настройте разрешение, позволяющее только аутентифицированным пользователям добавлять комментарии.
- Анонимные пользователи могут читать посты, но не комментировать.
Теперь вы понимаете, как настраивать и кастомизировать разрешения в DRF. Использование этих механизмов позволяет строить безопасные и гибкие API.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ