Короткий ответ
Сначала DRF последовательно пробует классы из authentication_classes, пока один из них не определит пользователя (или не останется анонимный AnonymousUser), и только после этого применяются permission_classes, проверяющие права уже для определённого (в том числе анонимного) пользователя; при неуспехе разрешения клиент получает 401 (если не аутентифицирован) или 403 (если аутентифицирован, но прав не хватает).
Как это работает подробнее
Каждый класс аутентификации реализует метод authenticate(request), возвращающий пару (user, auth) либо None (если эта схема не применима к запросу, например нет нужного заголовка) либо выбрасывающий исключение AuthenticationFailed (если заголовок есть, но токен невалиден). Если ни один класс не аутентифицировал пользователя, request.user становится AnonymousUser. После этого DRF проверяет каждый permission_class.has_permission(request, view) по очереди — первое False прерывает обработку.
Пример кода
from rest_framework.views import APIView
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class OrdersView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request):
return Response({"user": request.user.username})
# Без заголовка Authorization -> 401
# С валидным токеном, но IsAdminUser вместо IsAuthenticated и обычным пользователем -> 403Что использовать на практике
- Практика. Код статуса ошибки зависит от того, есть ли хоть один заголовок
WWW-Authenticateв выбранной схеме аутентификации: если пользователь не аутентифицирован и выбранная схема поддерживает401, вернётся401 Unauthorized; если пользователь аутентифицирован, но у него не хватает прав —403 Forbidden. На этом построена логика, например,IsAuthenticated(проверяет, чтоrequest.user.is_authenticated) противIsAdminUser(дополнительно проверяетis_staff).
Подводные камни
- Риск. Путают
401и403, возвращая403для полностью неаутентифицированных запросов; подключают несколько конфликтующих схем аутентификации без понимания порядка их применения, из-за чего непонятно, какая именно схема «съела» запрос и не дала следующей шанс.