Пользовательские разрешения
Для нашего первого пользовательского разрешения мы хотим ограничить доступ так, чтобы только автор записи в блоге мог редактировать или удалять его.
Суперпользователь admin будет иметь доступ ко всему, но обычный пользователь может только обновлять/удалять свой собственный контент.
Внутри Django REST Framework опирается на класс BasePermission, от которого наследуются все остальные классы разрешений. Все встроенные параметры разрешений, такие как AllowAny или IsAuthenticated просто расширяют BasePermission.
class BasePermission(object):
"""
Базовый класс, от которого должны наследоваться все классы разрешений.
"""
def has_permission(self, request, view):
"""
Возвращает `True`, если разрешение предоставлено, `False` в противном случае.
"""
return True
def has_object_permission(self, request, view, obj):
"""
Возвращает `True`, если разрешение предоставлено, `False` в противном случае.
"""
return True
Для пользовательского класса разрешений вы можете переопределить один или оба этих метода.
has_permission работает на представлениях списка, в то время как представления деталей выполняют оба метода:
Сначала has_permission, а затем, если это проходит, has_object_permission.
Настоятельно рекомендуется всегда задавать оба метода явно, потому что каждый из них по умолчанию имеет значение True.
В нашем случае мы хотим, чтобы только автор записи в блоге имел права на редактирование или удаление.
Мы также хотим ограничить просмотр списка только для чтения аутентифицированными пользователями.
Для этого мы создадим новый файл blog_api/permissions.py и заполним его следующим кодом:
from rest_framework import permissions
class IsAuthorOrReadOnly(permissions.BasePermission):
def has_permission(self, request, view):
# Только аутентифицированные пользователи могут видеть представление списка
if request.user.is_authenticated:
return True
return False
def has_object_permission(self, request, view, obj):
# Разрешение на чтение разрешено для любого запроса, поэтому мы всегда будем
# разрешать запросы GET, HEAD или OPTIONS
if request.method in permissions.SAFE_METHODS:
return True
# Права на запись разрешены только автору сообщения или администратору
return obj.author == request.user or request.user.is_staff
Мы создаем пользовательский класс IsAuthorOrReadOnly, который расширяет BasePermission.
Первый метод, has_permission, требует, чтобы пользователь вошел в систему, чтобы иметь доступ.
Второй метод, has_object_permission, разрешает запросы только на чтение, но ограничивает права на запись только автором записи в блоге. Мы получаем доступ к полю author через obj.author и к текущему пользователю через request.user.
Вернемся к файлу views.py и добавим новое разрешение в permission_classes для PostDetail и PostList. И не забываем удалить или закомментировать строчку permission_classes = (permissions.IsAdminUser,):
......
from .permissions import IsAuthorOrReadOnly # new
......
...
class PostList(generics.ListCreateAPIView):
permission_classes = (IsAuthorOrReadOnly,) # new
queryset = Post.objects.all()
serializer_class = PostSerializer
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = ['author']
search_fields = ['body', 'author__profile__bio']
ordering_fields = ['author_id', 'publish']
ordering = ['body']
pagination_class = StandardResultsSetPagination
...
...
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = (IsAuthorOrReadOnly,) # new
queryset = Post.objects.all()
serializer_class = PostSerializer
# permission_classes = (permissions.IsAdminUser,)
Давайте проверим работу наших прав доступа, для этого авторизуемся под администратором и проверим наш список постов:
Мы видим что у администратора есть все права, он может редактировать любой пост нашего блога.
Теперь выйдем из под аккаунта администратора и зайдем под пользователем. И перейдем к детальному просмотру поста, в моем случае по ссылке http://127.0.0.1:8000/api/1/:
И мы видим, что мы можем просматривать детальное отображение постов.
Но если мы перейдем к посту, который был создан от этого пользователя, в моем случае это http://127.0.0.1:8000/api/9/:
Установка надлежащих разрешений - очень важная часть любого API.
В качестве общей стратегии, хорошей идеей является установка строгой политики разрешений на уровне проекта, чтобы только аутентифицированные пользователи могли просматривать API.
Затем сделать разрешения на уровне представления или пользовательские разрешения более доступными по мере необходимости.