Сьогодні ми перейдемо до наступного важливого аспекту безпеки в 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"
- Якщо ваш view використовує дозвіл, а ви не налаштували механізм аутентифікації, DRF видасть помилку. Переконайтесь, що у
settings.pyвказаноDEFAULT_AUTHENTICATION_CLASSES.
- Якщо ваш view використовує дозвіл, а ви не налаштували механізм аутентифікації, DRF видасть помилку. Переконайтесь, що у
Дозвіл на рівні об'єкта
- Методи рівня об'єкта
has_object_permissionне викликаються для списків (list). Якщо потрібно застосувати логіку, фільтруйте QuerySet у методіget_queryset().
- Методи рівня об'єкта
Забули про
check_object_permissions()- Якщо ви використовуєте об'єктні дозволи, не забудьте вручну викликати
check_object_permissions.
- Якщо ви використовуєте об'єктні дозволи, не забудьте вручну викликати
Практичне завдання
Як створити дозволи для блогу? Потрібно виконати такі кроки:
- Створіть моделі
PostіComment. У кожного записуPostмає бути полеauthor. - Налаштуйте дозвіл, що дозволяє лише власнику посту його редагувати.
- Налаштуйте дозвіл, що дозволяє лише аутентифікованим користувачам додавати коментарі.
- Анонімні користувачі можуть читати пости, але не коментувати.
Тепер ти розумієш, як налаштовувати та кастомізувати дозволи в DRF. Використання цих механізмів дозволяє будувати безпечні та гнучкі API.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ