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"

    • Якщо ваш view використовує дозвіл, а ви не налаштували механізм аутентифікації, 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.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ