Авторизация
Авторизация должна быть подключаемой.
— Jacob Kaplan-Moss, «Худшие практики REST»
Авторизация — это механизм сопоставления входящего запроса с набором идентификационных данных, таких как пользователь, от которого исходит запрос, или токен, с помощью которого он был подписан. Политики разрешений и лимитирования запросов затем могут использовать эти данные для определения того, разрешен ли запрос.
REST фреймворк предоставляет несколько схем аутентификации из коробки, а также позволяет реализовывать пользовательские схемы.
Авторизация всегда выполняется в самом начале обработки представления, до проверки разрешений и лимитирования запросов, и до начала выполнения любого другого кода.
Свойство request.user обычно устанавливается в экземпляр класса User из пакета contrib.auth.
Свойство request.auth используется для дополнительной информации об авторизации, например, для представления токена, с помощью которого был подписан запрос.
Примечание: Не забывайте, что сама авторизация не разрешает или запрещает входящий запрос, она просто идентифицирует данные, используемые для аутентификации запроса.
Дополнительную информацию о настройке политик разрешений для вашего API вы найдете в документации по разрешениям.
Как определяется авторизация
Схемы авторизации всегда определяются как список классов. REST фреймворк попытается выполнить авторизацию с помощью каждого класса в списке и установит request.user и request.auth, используя значение, возвращаемое первым классом, который успешно выполнит авторизацию.
Если ни один класс не выполнил авторизацию, request.user будет установлено в экземпляр django.contrib.auth.models.AnonymousUser, а request.auth — в None.
Значение request.user и request.auth для неавторизованных запросов может быть изменено с помощью настроек UNAUTHENTICATED_USER и UNAUTHENTICATED_TOKEN.
Настройка схемы авторизации
Стандартные схемы авторизации могут быть установлены глобально, используя настройку DEFAULT_AUTHENTICATION_CLASSES. Например:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
]
}
Вы также можете установить схему авторизации на уровне представления или набора представлений, используя классовые представления APIView.
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'user': str(request.user), # `django.contrib.auth.User` instance.
'auth': str(request.auth), # None
}
return Response(content)
Или, если вы используете декоратор @api_view с представлениями на основе функций.
@api_view(['GET'])
@authentication_classes([SessionAuthentication, BasicAuthentication])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):
content = {
'user': str(request.user), # `django.contrib.auth.User` instance.
'auth': str(request.auth), # None
}
return Response(content)
Ответы «Не авторизован» и «Запрещено»
Когда неавторизованный запрос отклоняется из-за отсутствия разрешения, могут быть уместны два различных кода ошибки.
Ответы HTTP 401 всегда должны содержать заголовок WWW-Authenticate, который указывает клиенту, как выполнить авторизацию. Ответы HTTP 403 не содержат заголовок WWW-Authenticate.
Тип ответа зависит от схемы авторизации. Хотя может быть несколько схем авторизации, только одна используется для определения типа ответа. При определении типа ответа используется первый класс авторизации, установленный в представлении.
Обратите внимание, что если запрос успешно выполняет авторизацию, но все же лишен разрешения на выполнение запроса, то используется ответ 403 Permission Denied, независимо от схемы авторизации.
Конфигурация, специфичная для Apache mod_wsgi
Обратите внимание, что при развертывании на Apache с использованием mod_wsgi заголовок авторизации по умолчанию не передается в WSGI-приложение, так как предполагается, что авторизация будет обрабатываться Apache, а не на уровне приложения.
Если вы развертываете на Apache и используете любой метод аутентификации, не основанный на сессиях, вам необходимо явно настроить mod_wsgi для передачи необходимых заголовков в приложение. Это можно сделать, указав директиву WSGIPassAuthorization в соответствующем контексте и установив ее значение в 'On'.
# this can go in either server config, virtual host, directory or .htaccess WSGIPassAuthorization On
Справочник по API
BasicAuthentication
Данная схема авторизации использует HTTP Basic Authentication, подписывая запрос по имени пользователя и паролю. Basic Authentication, как правило, подходит только для тестирования.
При успешной авторизации BasicAuthentication предоставляет следующие учетные данные.
-
request.userбудет экземпляром DjangoUser. -
request.authбудетNone.
Неавторизованные запросы, отклоняемые из-за отсутствия разрешения, приведут к ответу HTTP 401 Unauthorized с соответствующим заголовком WWW-Authenticate. Например:
WWW-Authenticate: Basic realm="api"
Примечание: Если вы используете BasicAuthentication в рабочей среде, убедитесь, что ваш API доступен только по https. Также убедитесь, что ваши клиенты API всегда заново запрашивают имя пользователя и пароль при входе в систему и никогда не сохраняют эти данные в постоянном хранилище.
TokenAuthentication
Примечание: Авторизация токенов, предоставляемая Django REST framework, — это довольно простая реализация.
Для реализации, которая позволяет использовать более одного токена на пользователя, имеет более строгие детали реализации безопасности и поддерживает истечение срока действия токена, обратитесь к стороннему пакету Django REST Knox.
Эта схема авторизации использует простую схему HTTP-аутентификации на основе токена. Авторизация токенов подходит для клиент-серверных настроек, таких как настольные и мобильные клиенты.
Для использования схемы TokenAuthentication вам нужно настроить классы авторизации, включив TokenAuthentication, и дополнительно включить rest_framework.authtoken в настройку INSTALLED_APPS:
INSTALLED_APPS = [
...
'rest_framework.authtoken'
]
Убедитесь, что после изменения настроек выполнена команда manage.py migrate.
Приложение rest_framework.authtoken предоставляет миграции базы данных Django.
Вам также нужно создать токены для ваших пользователей.
from rest_framework.authtoken.models import Token token = Token.objects.create(user=...) print(token.key)
Для аутентификации клиентов ключ токена должен быть включен в заголовок HTTP Authorization. Ключ должен быть префиксам строкой «Token», с пробелом между двумя строками. Например:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
Если вы хотите использовать другое ключевое слово в заголовке, например Bearer, просто создайте подкласс TokenAuthentication и установите переменную класса keyword.
При успешной авторизации TokenAuthentication предоставляет следующие учетные данные.
-
request.userбудет экземпляром DjangoUser. -
request.authбудет экземпляромrest_framework.authtoken.models.Token.
Неавторизованные запросы, отклоняемые из-за отсутствия разрешения, приведут к ответу HTTP 401 Unauthorized с соответствующим заголовком WWW-Authenticate. Например:
WWW-Authenticate: Token
Утилита командной строки curl может быть полезной для тестирования API с аутентификацией по токенам. Например:
curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'
Примечание: Если вы используете TokenAuthentication в рабочей среде, убедитесь, что ваш API доступен только по https.
Генерация токенов
С помощью сигналов
Если вы хотите, чтобы каждый пользователь имел автоматически сгенерированный токен, вы можете просто перехватить сигнал post_save пользователя.
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
Обратите внимание, что вам нужно разместить этот фрагмент кода в установленном модуле models.py или в другом месте, который будет импортирован Django при запуске.
Если вы уже создали пользователей, вы можете сгенерировать токены для всех существующих пользователей следующим образом:
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
for user in User.objects.all():
Token.objects.get_or_create(user=user)
Через конечную точку API
При использовании TokenAuthentication, вы можете предоставить механизм для получения токена клиентами, используя имя пользователя и пароль. REST фреймворк предоставляет встроенное представление для обеспечения такого поведения. Чтобы использовать его, добавьте представление obtain_auth_token в свой URLconf:
from rest_framework.authtoken import views
urlpatterns += [
path('api-token-auth/', views.obtain_auth_token)
]
Обратите внимание, что часть URL в шаблоне может быть любой.
Представление obtain_auth_token вернет JSON-ответ при валидном username и password полях, отправленных в представление через данные формы или JSON:
{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }
Обратите внимание, что представление obtain_auth_token по умолчанию явно использует JSON-запросы и ответы, а не использует классы рендереров и парсеров по умолчанию в ваших настройках.
По умолчанию к представлению obtain_auth_token не применяются разрешения или лимиты запросов. Если вы хотите применить лимиты запросов, вам нужно переопределить класс представления и включить их в атрибут throttle_classes.
Если вам нужна настраиваемая версия представления obtain_auth_token, вы можете сделать это, создав подкласс класса представления ObtainAuthToken, и использовать его в вашем файле urlconf вместо этого.
Например, вы можете возвращать дополнительную информацию о пользователе помимо значения token:
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
class CustomAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data,
context={'request': request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({
'token': token.key,
'user_id': user.pk,
'email': user.email
})
А в вашем urls.py:
urlpatterns += [
path('api-token-auth/', CustomAuthToken.as_view())
]
С помощью админ панели Django
Также можно вручную создавать токены через админ-панель. В случае большой базы пользователей рекомендуется мокенитировать класс TokenAdmin для настройки по вашим потребностям, в частности, объявлением поля user как raw_field.
your_app/admin.py:
from rest_framework.authtoken.admin import TokenAdmin TokenAdmin.raw_id_fields = ['user']
Использование команды Django manage.py
С версии 3.6.4 можно сгенерировать токен пользователя с помощью следующей команды:
./manage.py drf_create_token <username>
Эта команда вернёт API-токен для данного пользователя, создав его, если он не существует:
Generated token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b for user user1
В случае, если нужно перегенерировать токен (например, если он был взломан или раскрыт), можно передать дополнительный параметр:
./manage.py drf_create_token -r <username>
SessionAuthentication
Эта схема авторизации использует стандартный бэкенд сессий Django для авторизации. Авторизация сессий подходит для AJAX-клиентов, работающих в том же контексте сессии, что и ваш веб-сайт.
При успешной авторизации SessionAuthentication предоставляет следующие учетные данные.
-
request.userбудет экземпляром DjangoUser. -
request.authбудетNone.
Неавторизованные запросы, отклоняемые из-за отсутствия разрешения, приведут к ответу HTTP 403 Forbidden.
Если вы используете API в стиле AJAX с SessionAuthentication, вам необходимо убедиться, что вы включаете действительный маркер CSRF для всех вызовов HTTP-методов «unsafe», таких как PUT, PATCH, POST или DELETE запросы. Подробнее см. в документации Django по CSRF.
Предупреждение: всегда используйте стандартный вид входа Django при создании страниц входа. Это гарантирует, что ваши страницы входа будут должным образом защищены.
Валидация CSRF в REST framework работает немного иначе, чем в стандартном Django, из-за необходимости поддерживать аутентификацию как на основе сессий, так и без сессий для одних и тех же представлений. Это означает, что только аутентифицированные запросы требуют маркеров CSRF, а анонимные запросы могут отправляться без них. Это поведение не подходит для страниц входа, для которых всегда должна быть применена валидация CSRF.
RemoteUserAuthentication
Эта схема аутентификации позволяет делегировать аутентификацию вашему веб-серверу, который устанавливает переменную окружения REMOTE_USER.
Для использования вам необходимо иметь django.contrib.auth.backends.RemoteUserBackend (или подкласс) в настройке AUTHENTICATION_BACKENDS. По умолчанию RemoteUserBackend создаёт User объекты для имен пользователей, которые ещё не существуют. Чтобы изменить это и другое поведение, обратитесь к документации Django.
При успешной аутентификации RemoteUserAuthentication предоставляет следующие данные:
-
request.userбудет экземпляром DjangoUser. -
request.authбудетNone.
Обратитесь к документации вашего веб-сервера за информацией о настройке метода аутентификации, например:
Настройка аутентификации
Чтобы реализовать собственную схему аутентификации, создайте подкласс BaseAuthentication и переопределите метод .authenticate(self, request). Метод должен возвращать кортеж из двух элементов (user, auth), если аутентификация прошла успешно, или None в противном случае.
В некоторых случаях вместо возвращения None вы можете вызвать исключение AuthenticationFailed из метода .authenticate().
Обычно следует придерживаться следующего подхода:
- Если попытка аутентификации не производится, верните
None. Другие схемы аутентификации также будут проверены. - Если попытка аутентификации была предпринята, но не увенчалась успехом, вызовите исключение
AuthenticationFailed. Ответ об ошибке будет возвращен немедленно, независимо от проверок разрешений и без проверки других схем аутентификации.
Вы можете также переопределить метод .authenticate_header(self, request). Если он реализован, он должен вернуть строку, которая будет использоваться в качестве значения заголовка WWW-Authenticate в ответе HTTP 401 Unauthorized.
Если метод .authenticate_header() не переопределён, схема аутентификации вернёт ответы HTTP 403 Forbidden при отказе в доступе к неаутентифицированному запросу.
Примечание: Когда ваш пользовательский аутентификатор вызывается свойствами объекта запроса .user или .auth, вы можете увидеть исключение AttributeError как WrappedAttributeError. Это необходимо для предотвращения подавления исходного исключения внешним доступом к свойству. Python не распознает, что исключение AttributeError исходит от вашего пользовательского аутентификатора, и вместо этого предположит, что объект запроса не имеет свойств .user или .auth. Эти ошибки должны быть исправлены или обработаны вашим аутентификатором.
Пример
В следующем примере любой входящий запрос будет аутентифицирован как пользователь, заданный именем пользователя в пользовательском заголовке запроса с именем 'X-USERNAME'.
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions
class ExampleAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
username = request.META.get('HTTP_X_USERNAME')
if not username:
return None
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
raise exceptions.AuthenticationFailed('No such user')
return (user, None)
Пакеты сторонних разработчиков
Доступны также следующие пакеты сторонних разработчиков.
django-rest-knox
Django-rest-knox библиотека предоставляет модели и представления для обработки аутентификации на основе токенов более безопасным и расширяемым способом, чем встроенная схема TokenAuthentication — с учетом одностраничных приложений и мобильных клиентов. Она обеспечивает токены на основе клиента, и представления для их генерации при предоставлении другой аутентификации (обычно аутентификации по умолчанию), удаления токена (предоставляя принудительный выход сервера) и удаления всех токенов (выход всех клиентов, в которых пользователь вошел).
Django OAuth Toolkit
Пакет Django OAuth Toolkit обеспечивает поддержку OAuth 2.0 и работает с Python 3.4+. Пакет поддерживается jazzband и использует превосходную библиотеку OAuthLib. Пакет хорошо документирован, поддерживается и в настоящее время является рекомендуемым пакетом для поддержки OAuth 2.0.
Установка и настройка
Установите с помощью pip.
pip install django-oauth-toolkit
Добавьте пакет в INSTALLED_APPS и измените настройки REST фреймворка.
INSTALLED_APPS = [
...
'oauth2_provider',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
]
}
Подробнее см. документацию Django REST framework — Начало работы.
Django REST framework OAuth
Пакет Django REST framework OAuth предоставляет поддержку как OAuth1, так и OAuth2 для REST framework.
Этот пакет ранее был включен непосредственно в REST framework, но теперь поддерживается и сопровождается как пакет сторонних разработчиков.
Установка и настройка
Установите пакет с помощью pip.
pip install djangorestframework-oauth
Подробные сведения о настройке и использовании см. в документации Django REST framework OAuth по аутентификации и разрешениям.
Аутентификация с использованием JSON Web Token
JSON Web Token — это относительно новый стандарт, который можно использовать для аутентификации на основе токенов. В отличие от встроенной схемы TokenAuthentication, аутентификация JWT не требует использования базы данных для проверки токена. Пакет для аутентификации JWT — djangorestframework-simplejwt, который предоставляет некоторые функции, а также плагиновую приложение для чёрного списка токенов.
Аутентификация HTTP Hawk
Библиотека HawkREST использует библиотеку Mohawk для работы с подписанными запросами и ответами Hawk в вашем API. Hawk позволяет двум сторонам безопасно общаться друг с другом с помощью сообщений, подписанных общим ключом. Он основан на HTTP MAC аутентификации доступа (которая была основана на частях OAuth 1.0).
Аутентификация HTTP Signature
HTTP Signature (на данный момент — черновик IETF) предоставляет способ достижения аутентификации источника и целостности сообщений для HTTP-сообщений. Похоже на схему Amazon HTTP Signature, используемую многими ее сервисами, она позволяет осуществлять аутентификацию на основе запроса без сохранения состояния. Elvio Toccalino поддерживает устаревший пакет djangorestframework-httpsignature, который обеспечивает простой в использовании механизм аутентификации HTTP Signature. Вы можете использовать обновленную вилку djangorestframework-httpsignature, которая является drf-httpsig.
Djoser
Djoser библиотека предоставляет набор представлений для обработки основных действий, таких как регистрация, вход, выход, сброс пароля и активация учетной записи. Пакет работает с настраиваемой моделью пользователя и использует аутентификацию на основе токенов. Это готовое к использованию REST-реализация системы аутентификации Django.
django-rest-auth / dj-rest-auth
Эта библиотека предоставляет набор конечных точек REST API для регистрации, аутентификации (включая аутентификацию в социальных сетях), сброса пароля, получения и обновления данных пользователя и т. д. Наличие этих конечных точек API позволяет вашим клиентским приложениям, таким как AngularJS, iOS, Android и др., взаимодействовать с вашим веб-сайтом Django на базе Django через REST API для управления пользователями.
В настоящее время существуют две вилки этого проекта.
- Django-rest-auth — оригинальный проект, но в настоящее время не обновляется.
- Dj-rest-auth — более новая вилка проекта.
drf-social-oauth2
Drf-social-oauth2 — фреймворк, который поможет вам аутентифицироваться с помощью основных социальных поставщиков OAuth2, таких как Facebook, Google, Twitter, Orcid и т. д. Он генерирует токены в формате JWT с лёгкой настройкой.
drfpasswordless
drfpasswordless добавляет (стилизованную под Medium и Square Cash) поддержку без пароля к схеме TokenAuthentication Django REST Framework. Пользователи входят и регистрируются с помощью токена, отправленного на контактную точку, такую как адрес электронной почты или номер мобильного телефона.
django-rest-authemail
django-rest-authemail предоставляет RESTful интерфейс API для регистрации и аутентификации пользователей. Для аутентификации используются адреса электронной почты вместо имен пользователей. Доступны API-конечные точки для регистрации, проверки электронной почты при регистрации, входа, выхода, сброса пароля, проверки сброса пароля, смены электронной почты, проверки смены электронной почты, смены пароля и получения данных пользователя. Включён полностью функциональный пример проекта и подробные инструкции.
Django-Rest-Durin
Django-Rest-Durin создан с идеей иметь одну библиотеку для аутентификации токенов для нескольких веб/CLI/мобильных API-клиентов через один интерфейс, но при этом позволяет различную конфигурацию токенов для каждого API-клиента, использующего API. Она предоставляет поддержку нескольких токенов на пользователя с помощью пользовательских моделей, представлений и разрешений, которые работают с Django-Rest-Framework. Время истечения срока действия токена может быть разным для каждого API-клиента и настраивается через интерфейс Django Admin.
Дополнительную информацию можно найти в документации.
Copyright © 2011–present Encode OSS Ltd.
Licensed under the BSD License.
https://www.django-rest-framework.org/api-guide/authentication/