Аутентификация

Auth должен быть подключаемым.

‒ Джейкоб Каплан-Мосс, «REST worst practices».

Аутентификация - это механизм связывания входящего запроса с набором идентификационных данных, таких как пользователь, от которого пришел запрос, или токен, которым он был подписан. Политики permission и throttling могут затем использовать эти учетные данные для определения того, должен ли запрос быть разрешен.

Фреймворк REST предоставляет несколько схем аутентификации из коробки, а также позволяет реализовать пользовательские схемы.

Аутентификация всегда выполняется в самом начале представления, до того, как произойдет проверка разрешений и дросселирования, и до того, как будет разрешено выполнение любого другого кода.

Свойство request.user обычно устанавливается на экземпляр класса contrib.auth пакета User.

Свойство request.auth используется для любой дополнительной информации об аутентификации, например, оно может быть использовано для представления маркера аутентификации, которым был подписан запрос.


Примечание: Не забывайте, что аутентификация сама по себе не разрешает и не запрещает входящий запрос, она просто идентифицирует полномочия, с которыми был сделан запрос.

Информацию о том, как настроить политику разрешений для вашего API, смотрите в разделе permissions documentation.


Как определяется аутентификация

Схемы аутентификации всегда задаются в виде списка классов. REST framework попытается аутентифицироваться с каждым классом в списке, и установит 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 Unauthorized

  • HTTP 403 Permission Denied

Ответы HTTP 401 всегда должны включать заголовок WWW-Authenticate, который указывает клиенту, как пройти аутентификацию. Ответы HTTP 403 не включают заголовок WWW-Authenticate.

Тип ответа, который будет использоваться, зависит от схемы аутентификации. Хотя может использоваться несколько схем аутентификации, для определения типа ответа может использоваться только одна схема. Первый класс аутентификации, установленный в представлении, используется при определении типа ответа.

Обратите внимание, что когда запрос может успешно пройти аутентификацию, но при этом получить отказ в разрешении на выполнение запроса, в этом случае всегда будет использоваться ответ 403 Permission Denied, независимо от схемы аутентификации.

Специфическая конфигурация Apache mod_wsgi

Обратите внимание, что при развертывании на :doc:`Apache using mod_wsgi <https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIPassAuthorization.html>`** , заголовок авторизации по умолчанию не передается в приложение WSGI, так как предполагается, что аутентификация будет обрабатываться Apache, а не на уровне приложения.

Если вы развертываете на Apache и используете любую аутентификацию, не основанную на сеансах, вам необходимо явно настроить mod_wsgi на передачу необходимых заголовков приложению. Это можно сделать, указав директиву WSGIPassAuthorization в соответствующем контексте и установив ее в значение 'On'.

# this can go in either server config, virtual host, directory or .htaccess
WSGIPassAuthorization On

Справочник по API

BasicAuthentication

Эта схема аутентификации использует :doc:`HTTP Basic Authentication <https://tools.ietf.org/html/rfc2617>`** , подписанную против имени пользователя и пароля. Базовая аутентификация обычно подходит только для тестирования.

При успешной аутентификации BasicAuthentication предоставляет следующие учетные данные.

  • request.user будет экземпляром Django User.

  • request.auth будет None.

Ответы без аутентификации, которым отказано в разрешении, приведут к ответу HTTP 401 Unauthorized с соответствующим заголовком WWW-Authenticate. Например:

WWW-Authenticate: Basic realm="api"

Примечание: Если вы используете BasicAuthentication в производстве, вы должны убедиться, что ваш API доступен только через https. Вы также должны убедиться, что клиенты вашего API всегда будут повторно запрашивать имя пользователя и пароль при входе в систему и никогда не будут сохранять эти данные в постоянном хранилище.

TokenAuthentication

Эта схема аутентификации использует простую схему HTTP-аутентификации на основе токенов. Токен-аутентификация подходит для клиент-серверных установок, таких как собственные настольные и мобильные клиенты.

Для использования схемы TokenAuthentication вам нужно configure the authentication classes включить 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 будет экземпляром Django User.

  • 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.


Генерация маркеров

С помощью сигналов

Если вы хотите, чтобы у каждого пользователя был автоматически сгенерированный Token, вы можете просто перехватить сигнал User’s 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 и используя его в url conf.

Например, вы можете вернуть дополнительную информацию о пользователе помимо значения 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 будет экземпляром Django User.

  • request.auth будет None.

Ответы без аутентификации, которым отказано в разрешении, приведут к ответу HTTP 403 Forbidden.

Если вы используете API в стиле AJAX с SessionAuthentication, вам нужно убедиться, что вы включили действительный CSRF-токен для любых «небезопасных» вызовов HTTP-метода, таких как PUT , PATCH , POST или DELETE запросы. Более подробную информацию смотрите в Django CSRF documentation.

Предупреждение: Всегда используйте стандартное представление входа Django при создании страниц входа. Это гарантирует, что ваши представления входа будут должным образом защищены.

Проверка CSRF в REST-фреймворке работает несколько иначе, чем в стандартном Django, из-за необходимости поддержки сеансовой и несеансовой аутентификации для одних и тех же представлений. Это означает, что только аутентифицированные запросы требуют CSRF-токенов, а анонимные запросы могут быть отправлены без CSRF-токенов. Такое поведение не подходит для представлений входа в систему, к которым всегда должна применяться проверка CSRF.

RemoteUserAuthentication

Эта схема аутентификации позволяет делегировать аутентификацию вашему веб-серверу, который устанавливает переменную окружения REMOTE_USER.

Чтобы использовать его, вы должны иметь django.contrib.auth.backends.RemoteUserBackend (или подкласс) в настройках AUTHENTICATION_BACKENDS. По умолчанию RemoteUserBackend создает User объекты для имен пользователей, которые еще не существуют. Чтобы изменить это и другое поведение, обратитесь к Django documentation.

При успешной аутентификации RemoteUserAuthentication предоставляет следующие учетные данные:

  • request.user будет экземпляром Django User.

  • 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 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 - Getting started.

Django REST framework OAuth

Пакет Django REST framework OAuth обеспечивает поддержку OAuth1 и OAuth2 для фреймворка REST.

Ранее этот пакет был включен непосредственно в REST framework, но теперь поддерживается и сопровождается как пакет стороннего разработчика.

Установка и настройка

Установите пакет с помощью pip.

pip install djangorestframework-oauth

Подробнее о конфигурации и использовании смотрите документацию по OAuth фреймворка Django REST для authentication и permissions.

Аутентификация по веб-точкам JSON

JSON Web Token - это довольно новый стандарт, который можно использовать для аутентификации на основе токенов. В отличие от встроенной схемы TokenAuthentication, аутентификация JWT не требует использования базы данных для проверки токена. Пакет для аутентификации JWT - это djangorestframework-simplejwt, который предоставляет некоторые возможности, а также подключаемое приложение черного списка токенов.

Аутентификация Hawk HTTP

Библиотека HawkREST основана на библиотеке Mohawk и позволяет вам работать с подписанными запросами и ответами Hawk в вашем API. Hawk позволяет двум сторонам безопасно общаться друг с другом, используя сообщения, подписанные общим ключом. Она основана на HTTP MAC access authentication (которая была основана на части :doc:`OAuth 1.0 <https://oauth.net/core/1.0a/>`** ).

Аутентификация подписи HTTP

HTTP Signature (в настоящее время IETF draft поддерживает пакет djangorestframework-httpsignature (устаревший), который предоставляет простой в использовании механизм HTTP Signature Authentication. Вы можете использовать обновленную версию форка djangorestframework-httpsignature.

Джосер

Библиотека Djoser предоставляет набор представлений для обработки основных действий, таких как регистрация, вход, выход, сброс пароля и активация учетной записи. Пакет работает с пользовательской моделью пользователя и использует аутентификацию на основе токенов. Это готовая к использованию REST-реализация системы аутентификации Django.

django-rest-auth / dj-rest-auth

Эта библиотека предоставляет набор конечных точек REST API для регистрации, аутентификации (включая аутентификацию в социальных сетях), сброса пароля, получения и обновления данных пользователя и т.д. Имея эти конечные точки API, ваши клиентские приложения, такие как AngularJS, iOS, Android и другие, могут самостоятельно общаться с вашим бэкенд-сайтом Django через REST API для управления пользователями.

В настоящее время существует два форка этого проекта.

  • Django-rest-auth - исходный проект, but is not currently receiving updates.

  • Dj-rest-auth - это более новый форк проекта.

django-rest-framework-social-oauth2

Библиотека Django-rest-framework-social-oauth2 предоставляет простой способ интеграции социальных плагинов (facebook, twitter, google и т.д.) в вашу систему аутентификации и легкую настройку oauth2. С помощью этой библиотеки вы сможете аутентифицировать пользователей на основе внешних токенов (например, токена доступа facebook), конвертировать эти токены в «собственные» токены oauth2, использовать и генерировать токены oauth2 для аутентификации ваших пользователей.

django-rest-knox

Библиотека Django-rest-knox предоставляет модели и представления для обработки аутентификации на основе токенов более безопасным и расширяемым способом, чем встроенная схема TokenAuthentication - с учетом одностраничных приложений и мобильных клиентов. Она предоставляет токены для каждого клиента, а также представления для их генерации при предоставлении другой аутентификации (обычно базовой), для удаления токена (обеспечивая принудительный выход с сервера) и для удаления всех токенов (выход из всех клиентов, в которые вошел пользователь).

drfpasswordless

drfpasswordless добавляет (по мотивам Medium, Square Cash) поддержку беспарольного входа в схему TokenAuthentication платформы Django REST Framework. Пользователи входят в систему и регистрируются с помощью токена, отправленного на контактную точку, например, адрес электронной почты или номер мобильного телефона.

django-rest-authemail

django-rest-authemail предоставляет RESTful API интерфейс для регистрации и аутентификации пользователей. Для аутентификации используются адреса электронной почты, а не имена пользователей. Доступны конечные точки API для регистрации, проверки электронной почты при регистрации, входа в систему, выхода из системы, сброса пароля, проверки сброса пароля, изменения электронной почты, проверки изменения электронной почты, изменения пароля и детализации пользователя. Полностью функциональный пример проекта и подробные инструкции прилагаются.

Джанго-Рест-Дурин

Django-Rest-Durin создана с идеей иметь одну библиотеку, которая выполняет аутентификацию токенов для нескольких Web/CLI/Mobile API клиентов через один интерфейс, но позволяет различную конфигурацию токенов для каждого API клиента, который потребляет API. Она обеспечивает поддержку нескольких токенов для каждого пользователя через пользовательские модели, представления, разрешения, которые работают с Django-Rest-Framework. Время истечения срока действия токена может быть разным для каждого API клиента и настраивается через интерфейс администратора Django.

Более подробную информацию можно найти в разделе Documentation.

Вернуться на верх