Права доступа и токены в DRF

⏱ 30 мин · 🧩 заданий: 6

Аутентификация и права в API

В API, как и на сайте, нужно знать, кто делает запрос (аутентификация) и что ему можно (права). DRF разделяет эти задачи:

  • классы аутентификации определяют request.user;
  • классы прав решают, пустить ли запрос.

Классы прав

Класс Кого пускает
AllowAny Всех
IsAuthenticated Только аутентифицированных
IsAuthenticatedOrReadOnly Читать — всех, менять — аутентифицированных
IsAdminUser Только is_staff
DjangoModelPermissions По правам модели (add/change/delete)

Глобально:

REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticatedOrReadOnly"],
}

Для класса:

class PostViewSet(viewsets.ModelViewSet):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]

Безопасные методы — GET, HEAD, OPTIONS (permissions.SAFE_METHODS): они ничего не меняют.

Своё право: только автор редактирует

# blog/api/permissions.py
from rest_framework import permissions


class IsAuthorOrReadOnly(permissions.BasePermission):
    message = "Редактировать пост может только его автор."

    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        return obj.author == request.user
  • has_permission(request, view) — проверка на уровне запроса (до получения объекта);
  • has_object_permission(request, view, obj) — проверка конкретного объекта (в detail-запросах).
class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsAuthorOrReadOnly]

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

Все права из списка должны разрешить запрос.

Способы аутентификации

SessionAuthentication

Использует сессию Django — удобно для Browsable API и фронтенда на том же домене (нужен CSRF-токен).

TokenAuthentication

Простой постоянный токен для каждого пользователя:

INSTALLED_APPS += ["rest_framework.authtoken"]

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework.authentication.SessionAuthentication",
        "rest_framework.authentication.TokenAuthentication",
    ],
    ...
}
python manage.py migrate
python manage.py drf_create_token admin

Получение токена по логину и паролю:

from rest_framework.authtoken.views import obtain_auth_token

urlpatterns = [
    path("api-token-auth/", obtain_auth_token),
]
curl -X POST -d "username=admin&password=secret" http://127.0.0.1:8000/api/api-token-auth/
# {"token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b"}

curl -H "Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" \
     -X POST -H "Content-Type: application/json" \
     -d '{"title": "Пост из API", "slug": "post-iz-api", "body": "Текст"}' \
     http://127.0.0.1:8000/api/posts/

JWT (JSON Web Token)

Стандарт для SPA и мобильных приложений — пакет djangorestframework-simplejwt:

pip install djangorestframework-simplejwt
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "rest_framework_simplejwt.authentication.JWTAuthentication",
    ],
}
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

urlpatterns = [
    path("token/", TokenObtainPairView.as_view()),
    path("token/refresh/", TokenRefreshView.as_view()),
]

Клиент получает пару: короткоживущий access (минуты) и долгоживущий refresh (дни). Запросы идут с Authorization: Bearer <access>; когда access истёк, клиент получает новый по refresh. JWT подписан сервером и содержит id пользователя, поэтому проверяется без запроса к базе.

Token JWT
Хранение В базе Не нужно (подпись)
Срок жизни Бессрочный Ограниченный
Отзыв Удалить из базы Сложнее (blacklist)

Только HTTPS

Токен — это ключ от аккаунта. Передавайте его только по HTTPS и никогда в адресе запроса.

Ограничение частоты запросов (throttling)

REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_CLASSES": [
        "rest_framework.throttling.AnonRateThrottle",
        "rest_framework.throttling.UserRateThrottle",
    ],
    "DEFAULT_THROTTLE_RATES": {"anon": "100/day", "user": "1000/day"},
}

При превышении — ответ 429 Too Many Requests. Защищает от перебора паролей и злоупотреблений.

Итог

  • Аутентификация определяет request.user, права решают, пускать ли запрос.
  • IsAuthenticatedOrReadOnly + своё объектное право IsAuthorOrReadOnly — типичная схема для блога.
  • Токены: TokenAuthentication (просто) или JWT (simplejwt, access/refresh).
  • Throttling ограничивает частоту запросов.

Практика решено 0 из 6

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Один вариант ответа

Какое право разрешает читать всем, а изменять — только аутентифицированным пользователям?

Задание 2 Написать код

Напишите право IsAuthorOrReadOnly (наследник permissions.BasePermission): метод has_object_permission(self, request, view, obj) разрешает безопасные методы (permissions.SAFE_METHODS) всем, а остальные — только если obj.author == request.user.

Задание 3 Написать код

Примените к PostViewSet права: IsAuthenticatedOrReadOnly и ваш IsAuthorOrReadOnly.

Задание 4 Один вариант ответа

Как клиент передаёт токен DRF (TokenAuthentication) в запросе?

Задание 5 Написать код

Подключите endpoint получения токена по логину и паролю: маршрут api-token-auth/ со встроенным представлением obtain_auth_token.

Задание 6 Несколько вариантов

Чем JWT отличается от простого токена DRF (TokenAuthentication)?

Войдите, чтобы отмечать пройденные уроки.