Руководство по API платформы Django REST (13): аутентификация

задняя часть Python API Django

Официальная оригинальная ссылка
Эта серия статей адрес github
Пожалуйста, укажите источник

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

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

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

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

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

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


Уведомление:не забудьте,Сама аутентификация не (Разрешить или не позволяет) входящие запросы, который просто определяет учетные данные для запроса.


Как определить аутентификацию

Схемы аутентификации всегда определяются как список классов. Платформа REST попытается пройти аутентификацию с каждым классом в списке и будет использовать возвращаемое значение первого класса, который успешно прошел аутентификацию, чтобы установитьrequest.userиrequest.auth.

Если нет класса для аутентификации, он будетrequest.userУстановить какdjango.contrib.auth.models.AnonymousUserэкземпляр и будетrequest.authУстановить какNone.

можно использоватьUNAUTHENTICATED_USERиUNAUTHENTICATED_TOKENУстановите модификацию неаутентифицированных запросовrequest.userиrequest.authзначение .

Настроить схему аутентификации

Можно использовать схему аутентификации по умолчанию.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': unicode(request.user),  # `django.contrib.auth.User` instance.
            'auth': unicode(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': unicode(request.user),  # `django.contrib.auth.User` instance.
        'auth': unicode(request.auth),  # None
    }
    return Response(content)

Несанкционированные и запрещенные ответы

Существует два разных кода ошибки, которые могут быть уместны, когда запрос, не прошедший проверку подлинности, отклонен.

  • [HTTP 401 Unauthorized][http401]
  • [HTTP 403 Permission Denied][http403]

Ответы 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 и подписывается на основе имени пользователя и пароля. Обычная аутентификация обычно подходит только для тестирования.

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

  • request.userДжангоUserсила.
  • request.authдаNone.

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

WWW-Authenticate: Basic realm="api"

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

TokenAuthentication

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

нужно использоватьTokenAuthenticationсхемы, вам нужно настроить класс аутентификации, чтобы он содержалTokenAuthentication, И вINSTALLED_APPSТакже включается в настройкахrest_framework.authtoken:

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

Для аутентификации клиента ключ токена должен содержаться вAuthorizationв заголовке HTTP. Перед ключевым словом должен стоять строковый литерал "Token" с пробелом, разделяющим две строки. Например:

Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

Уведомление:Если вы хотите использовать разные ключевые слова в заголовке (например,Bearer), просто подклассTokenAuthenticationи установитьkeywordпеременная класса.

В случае успешной аутентификацииTokenAuthenticationБудут предоставлены следующие учетные данные.

  • request.userДжанго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доступ.


сгенерировать токен

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

Если вы хотите, чтобы у каждого пользователя был автоматически сгенерированный токен, просто запишите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 += [
    url(r'^api-token-auth/', views.obtain_auth_token)
]

Обратите внимание, что URL-часть шаблона может быть чем угодно.

Когда данные формы действительны или JSONusernameиpasswordКогда поле публикуется в представлении,obtain_auth_tokenПредставление вернет ответ JSON:

{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }

Обратите внимание, что по умолчаниюobtain_auth_tokenПредставления явно используют запросы и ответы JSON вместо заданных вами классов отрисовщика и парсера по умолчанию.

По умолчанию никакие разрешения или ограничения не применяются кobtain_auth_tokenПосмотреть.如果您希望应用 throttling ,则需要重写视图类,并使用throttle_classesсвойства содержат их.

если вам нужно настроитьobtain_auth_tokenвид, вы можете наследовать отObtainAuthTokenПросмотрите класс, чтобы реализовать и использовать его в своей конфигурации URL.

Например, вы можете вернуть превышение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 += [
    url(r'^api-token-auth/', CustomAuthToken.as_view())
]
Используйте админку Джанго

Токены также можно создавать вручную через интерфейс администратора. Если вы используете большую базу пользователей, мы рекомендуем вам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ДжангоUserпример.
  • request.authдаNone.

Отклонение неаутентифицированных ответов приведет кHTTP 403 Forbiddenотклик.

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

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

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

RemoteUserAuthentication

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

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

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

  • request.userДжангоUserпример.
  • request.authдаNone.

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

пользовательская аутентификация

Чтобы реализовать пользовательскую схему аутентификации, наследуйтеBaseAuthenticationи переписать.authenticate(self, request)метод. Если аутентификация прошла успешно, метод должен вернуть(user, auth)2-кортеж из , иначе возвратNone.

В некоторых случаях вы можете захотеть.authenticate()броски методаAuthenticationFailedисключение вместо возвратаNone.

Обычно подход, который вы должны использовать, следующий:

  • Возвращает, если попытка аутентификации не предпринималасьNone. Любая другая используемая схема аутентификации по-прежнему будет проверяться.
  • Повышение, если попытка аутентификации не удаласьAuthenticationFailedаномальный. Независимо от того, проверяются ли какие-либо разрешения, ответ об ошибке будет возвращен немедленно, и никакие другие схемы проверки подлинности не проверяются.

ты тожеМожетпереписать.authenticate_header(self, request)метод. Если он реализован, он должен возвращать строку, которая будет использоваться какHTTP 401 UnauthorizedЗначение заголовка WWW-Authenticate в ответе.

если не покрыт.authenticate_header()Метод, затем, когда неанатурные запросы отказаны доступом, схема аутентификации возвращаетHTTP 403 Forbiddenотклик.


Note:когда объект запроса.userили.authсвойство для вызова вашего пользовательского аутентификатора, вы можете увидетьAttributeErrorв видеWrappedAttributeErrorповторно повышается. Это необходимо для предотвращения подавления исходного исключения при доступе к внешнему свойству. Питон не распознает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('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)