[перевод] аутентификация на основе json web token в django и angularjs: часть первая / хабр

Introduction

This is the first article in a multipart series on implementing the Django authentication system. To aid in the demonstration of the many features of Django authentication I will be building a demo survey application which I’ll call Django Survey throughout these tutorials.

401 и 403 ответы

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

Django oauth toolkit

Пакет Django OAuth Toolkit обеспечивает поддержку OAuth 2.0 и работает с Python 3.4 . Пакет поддерживается Evonove и использует превосходную OAuthLib. Пакет хорошо документирован, хорошо поддерживается и в настоящее время является нашим рекомендуемым пакетом для поддержки OAuth 2.0.

Django oauth2 consumer

Библиотека Django OAuth2 Consumer от Rediker Software – это еще один пакет для OAuth 2.0.

Django rest framework

Теперь нужно установить Django REST Framework. Django REST Framework большой проект с открытым исходным кодом, для тех, кто хочет создавать одностраничные приложения и API для них.

Мы не будем детально рассматривать, как работает Django REST Framework, поэтому если вы не знакомы с ним, посмотрите документацию.

Для установки Django REST Framework, выполните следующую команду:

$ pip install djangorestframework

Django REST Framework должен быть добавлен к вашим установленным приложениям (INSTALLED_APPS в django_angular_token_auth/settings.py:)

INSTALLED_APPS = (
    ...,
    'rest_framework',
)

Так же необходимо добавить следующие параметры в django_angular_token_auth/settings.py:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ), 
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}

Мы не будем использовать SessionAuthentication или BasicAuthentication, но они имеются в Django REST Framework и предлагают работоспособный API из коробки.

Django rest framework oauth

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

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

Django-rest-auth

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

Django-rest-authemail¶

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

Django-rest-framework-jwt

Последнее, что нужно сделать, это установить django-rest-framework-jwt. Этот пакет обеспечивает поддержку JWT для Django REST Framework и в качестве JSON Web Token использует реализацию PyJWT. Что бы установить django-rest-framework-jwt выполните следующую команду:

$ pip install djangorestframework-jwt

Нужно будет добавить следующие параметры в django_angular_token_auth/settings.py:

import datetime
JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=14)
}

Этот параметр указывает срок жизни для наших маркеров и в нашем случае это будет 14 дней. Вы можете изменить его, исходя из собственных предпочтений.

Вы так же должны добавить обновленные настройки REST_FRAMEWORK:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
   )
}

Обратите внимание, что мы добавили:’rest_framework_jwt.authentication.JSONWebTokenAuthentication’, в ‘DEFAULT_AUTHENTICATION_CLASSES’.

Django-rest-knox

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

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

Drfpasswordless

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

High level approach (using the stock django loginview)

Over in survey/urls.py I locate the login url path and replace the custom built views.LoginView class with the builtin django.contrib.auth.views.LoginView and assign a parameter named template_name within the .as_view(…) method with the same survey/login.html template used previously.

# survey/urls.py

from django.contrib.auth import views as auth_views
from django.urls import path

from . import views

urlpatterns = [
  path('register/', views.RegisterView.as_view(), name='register'),
  path('login/', auth_views.LoginView.as_view(template_name='survey/login.html'), name='login'),
  path('profile/', views.ProfileView.as_view(), name='profile'),
  path('logout/', auth_views.LogoutView.as_view(), name='logout'),
]

Json web token аутентификация

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

Local enivironment setup for django development

To start off I create a Python3 virtual enviroment, activate it, pip install django and django-widget-tweaks (widget-tweaks is used for controlling the way forms are rendered).

python3 -m venv venv
source venv/bin/activate
(venv) $ pip install django django-widget-tweaks

After that I create a django_survey project, change directories into the resulting django_survey directory and, make a Django app named survey.

Url-адреса


Теперь нужно настроить URL-адреса для нашего проекта.

Откройте django_angular_token_auth/urls.py и приведите его к следующему виду:

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

Аутентификация должна быть подключаемой.

— Jacob Kaplan-Moss, “REST worst practices”

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

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

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

Во второй части

На этом мы остановимся. Во второй части, построим клиентское приложение и в основном сосредоточимся на регистрации и сеансе входа в систему. Напишем сервис, для того что бы можно было правильно заходить и выходить из системы.

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

Если вы хотите чтобы каждый пользователь получал сгенерированый токен, вы можете просто ловить сигнал post_save.

Заметьте что вы зохотите убедится что вы положили этот фрагмент кода в установленый models.py или друго место которое будет импортировано Джангой при старте.

Если вы уже создали некоторых пользоватей, вы можете сгенерировать токен для всех существующих пользователей так:

Когда используете TokenAuthentication вы возможно захотите предоставить клиентам механизм получения токена по имени пользователя и паролю. REST framework предоставляет встроенную функцию для этого. Чтобы использовать ее, добавьте obtain_auth_token в ваш URLconf:

Имейте в виду, что URL часть паттерная который вы можете не использовать.

obtain_auth_token будет возвращать JSON ответ когда получит валидное имя пользователя и пароль в POST запросе.

Имейте в виду, что по умолчанию obtain_auth_token явно использует JSON запросы и ответы, вместо использования по умолчанию визуализации и парсинга классов в ваших настройках. Если вам нужна своя версия obtain_auth_token, вы можете переопределить ObtainAuthToken класс и использовать его в ваших конфигурация url.

Другие источники аутентификации¶

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

Например, в вашей компании может быть уже установлена система LDAP, которая хранит имя пользователя и пароль для каждого сотрудника. Если бы пользователи имели отдельные учетные записи в LDAP и в приложениях на базе Django, это было бы хлопотно как для сетевого администратора, так и для самих пользователей.

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

Смотрите authentication backend reference для получения информации о бэкендах аутентификации, включенных в Django.

Указание бэкендов аутентификации

За кулисами Django ведет список «бэкендов аутентификации», которые он проверяет на предмет аутентификации. Когда кто-то вызывает django.contrib.auth.authenticate() – как описано в How to log a user in – Django пытается пройти аутентификацию через все свои бэкенды аутентификации. Если первый метод аутентификации не работает, Django пробует второй, и так далее, пока не будут испробованы все бэкенды.

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

По умолчанию AUTHENTICATION_BACKENDS имеет значение:

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

Порядок AUTHENTICATION_BACKENDS имеет значение, поэтому если одно и то же имя пользователя и пароль действительны в нескольких бэкендах, Django остановит обработку на первом положительном совпадении.

Если бэкенд вызывает исключение PermissionDenied, аутентификация немедленно завершится неудачей. Django не будет проверять последующие бэкенды.

Примечание

После того, как пользователь прошел аутентификацию, Django сохраняет, какой бэкенд был использован для аутентификации пользователя в его сессии, и повторно использует этот же бэкенд в течение всей сессии, когда требуется доступ к текущему аутентифицированному пользователю. Это фактически означает, что источники аутентификации кэшируются на основе каждой сессии, поэтому если вы измените AUTHENTICATION_BACKENDS, вам придется очистить данные сессии, если вам нужно заставить пользователей повторно аутентифицироваться с помощью других методов. Простой способ сделать это – выполнить Session.objects.all().delete().

Написание бэкенда аутентификации

Бэкэнд аутентификации – это класс, реализующий два обязательных метода: get_user(user_id) и authenticate(request,**credentials), а также набор необязательных методов, связанных с разрешениями authorization methods.

Метод get_user принимает user_id – который может быть именем пользователя, идентификатором базы данных или чем угодно, но должен быть первичным ключом вашего объекта user – и возвращает объект user или None.

Метод authenticate принимает аргумент request и учетные данные в качестве аргументов ключевых слов. В большинстве случаев это будет выглядеть следующим образом:

Но он также может аутентифицировать токен, например, так:

В любом случае, authenticate() должен проверить полученные учетные данные и вернуть объект пользователя, который соответствует этим учетным данным, если они действительны. Если они недействительны, он должен вернуть None.

request является HttpRequest и может быть None, если он не был предоставлен authenticate() (который передает его бэкенду).

Администратор Django тесно связан с Django User object. Лучший способ справиться с этим – создать объект Django User для каждого пользователя, который существует в вашем бэкенде (например, в вашем каталоге LDAP, вашей внешней базе данных SQL и т.д.) Вы можете либо написать скрипт, чтобы сделать это заранее, либо ваш метод authenticate может сделать это при первом входе пользователя.

Вот пример бэкенда, который аутентифицируется по переменной имени пользователя и пароля, определенной в вашем settings.py файле, и создает объект Django User при первой аутентификации пользователя:

Обработка авторизации в пользовательских бэкендах

Пользовательские бэкенды авторизации могут предоставлять свои собственные разрешения.

Модель пользователя и ее менеджер делегируют функции поиска разрешений (get_user_permissions(), get_group_permissions(), get_all_permissions(), has_perm(), has_module_perms() и with_perm()) любому бэкенду аутентификации, который реализует эти функции.

Разрешения, предоставляемые пользователю, будут представлять собой супермножество всех разрешений, возвращаемых всеми бэкендами. То есть, Django предоставляет пользователю разрешение, которое предоставляет любой из бэкендов.

Если бэкенд вызывает исключение PermissionDenied в has_perm() или has_module_perms(), авторизация будет немедленно провалена, и Django не будет проверять последующие бэкенды.

Бэкэнд может реализовать права доступа для волшебного администратора следующим образом:

Это дает полные полномочия пользователю, получившему доступ в приведенном выше примере. Обратите внимание, что в дополнение к тем же аргументам, которые передаются связанным функциям django.contrib.auth.models.User, все функции backend auth принимают в качестве аргумента объект user, который может быть анонимным пользователем.

Полную реализацию авторизации можно найти в классе ModelBackend в django/contrib/auth/backends.py, который является бэкендом по умолчанию и большую часть времени запрашивает таблицу auth_permission.

Авторизация для анонимных пользователей

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

Фреймворк разрешений Django не имеет места для хранения разрешений для анонимных пользователей. Однако объект user, передаваемый бэкенду аутентификации, может быть объектом django.contrib.auth.models.AnonymousUser, что позволяет бэкенду задавать пользовательское поведение авторизации для анонимных пользователей. Это особенно полезно для авторов повторно используемых приложений, которые могут делегировать все вопросы авторизации бэкенду auth, вместо того чтобы нуждаться в настройках, например, для контроля анонимного доступа.

Заголовок


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

Тип маркера хранится в ключе «typ». Ключ «typ» игнорируется в JWT (для этой статьи это не важно, но вы можете

, чтобы узнать почему). Если ключ «typ» присутствует, его значение должно быть JWT, чтобы указать, что этот объект является JSON Web Token.

Второй ключ «alg» определяет алгоритм, используемый для шифрования маркера. По умолчанию он должен быть установлен в HS256. Есть целый ряд альтернативных алгоритмов, которые используются в различных реализациях. Полный список с разбивкой по библиотекам можно посмотреть на JWT.io.

Заголовок кодируется в base64.

Используя команду django manage.py

Начиная с версии 3.6.4 можно сгенерировать токен пользователя с помощью следующей команды:

Эта команда вернет токен API для данного пользователя, создав его, если он не существует:

Если вы хотите перегенерировать токен (например, если он был взломан или случилась утечка), вы можете передать дополнительный параметр:

Класс sessionauthentication

Такая аутентификационная схема используется Джанго по умолчанию. Авторизация сессиями подходит для AJAX клиентов которые запускают одинаковый сессионный контекст как ваш сайт

Если успешно авторизовался, предоставляются следующие полномочия:

Класс tokenauthentication

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

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

Конкретная конфигурация apache mod_wsgi

Обратите внимание, что при развертывании на Apache с использованием mod_wsgi заголовок авторизации не передается в приложение WSGI по умолчанию, поскольку предполагается, что аутентификация будет выполняться Apache, а не на уровне приложения.

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

Настройка схемы аутентификации¶

Схемы аутентификации по умолчанию можно установить глобально, используя параметр DEFAULT_AUTHENTICATION_CLASSES. Например.

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

Или, если вы используете декоратор @api_view с представлениями, основанными на функциях.

Обработка авторизации в пользовательских бэкендах¶

Пользовательские бэкенды авторизации могут предоставлять свои собственные разрешения.

Пакеты сторонних производителей¶

Также доступны следующие пакеты сторонних производителей.

django-rest-authemail

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

Подпись

Когда у нас есть заголовок и полезная нагрузка, можно вычислить подпись.

Берутся закодированные в base64: заголовок и полезная нагрузка, они объединяются в строку через точку. Затем эта строка и секретный ключ поступает на вход алгоритма шифрования, указанного в заголовке (ключ «alg»). Ключом может быть любая строка. Более длинные строки будут наиболее предпочтительнее, поскольку потребуется больше времени на подбор.

Полезная нагрузка

В полезной нагрузке хранится любая информация, которую нужно проверить. Каждый ключ в полезной нагрузке известен как «заявление». К примеру, рассмотрим социальную сеть, в которой присоединиться к сообществу можно только по приглашению. Когда мы хотим пригласить кого-то в сообщество, мы отправляем ему письмо с приглашением.

{
    "email": "[email protected]"
}
 

Ключи в полезной нагрузке могут быть произвольными. Тем не менее, есть несколько зарезервированных, которые нужно знать:

JWT требует, чтобы во всех его реализациях маркеры с истекшим сроком действия отклонялись. В

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

Важно понимать, что полезная нагрузка не передается в зашифрованном виде (хотя, маркеры могут быть вложенными и тогда возможно передавать зашифрованные данные). Поэтому в ней нельзя хранить любую секретную информацию. Например, пароли, номера социального страхования и т.д.

Как и заголовок, полезная нагрузка кодируется в base64.

Пользовательские пользователи и разрешения¶

Чтобы упростить включение структуры разрешений Django в ваш собственный класс пользователя, Django предоставляет PermissionsMixin. Это абстрактная модель, которую вы можете включить в иерархию классов для вашей модели пользователя, предоставляя вам все методы и поля базы данных, необходимые для поддержки модели разрешений Django.

PermissionsMixin предоставляет следующие методы и атрибуты:

Пользовательские разрешения¶

Чтобы создать пользовательские разрешения для данного объекта модели, используйте permissionsmodel Meta attribute.

Этот пример модели Task создает два пользовательских разрешения, т.е. действия, которые пользователи могут или не могут выполнять с экземплярами Task, специфичными для вашего приложения:

Единственное, что это делает – создает эти дополнительные разрешения, когда вы выполняете manage.pymigrate (функция, создающая разрешения, подключена к сигналу post_migrate).

Ваш код отвечает за проверку значения этих разрешений, когда пользователь пытается получить доступ к функциональности, предоставляемой приложением (изменение статуса задач или закрытие задач). Продолжая пример выше, следующее проверяет, может ли пользователь закрывать задачи:

Представления

С сериализаторами разобрались, давайте теперь перейдем к представлениям.

Для наших целей нужно только одно представление, которое будет возвращать список объектов пользователя.


Django REST Framework предлагает целый ряд представлений, которые выполняют различные функции, например представление списка объектов одного типа. Такую функциональность предлагает класс ListAPIView.

Добавьте следующее в authentication/views.py:

Реализация проверки подлинности с помощью json web token

Давайте пойдем дальше и создадим наш проект.

Перейдите в каталог проекта и выполните команды:

Сериализаторы


Для проверки работоспособности API нужно отправлять какие-нибудь данные на AJAX запросы. Самый простой способ это сделать — отправить обратно данные пользователя в нашей системе.

Первое, что нужно сделать, это создать пользователя. Выполните следующую команду и следуйте инструкциям на экране:

Создание django приложения

Теперь давайте создадим приложение Django для хранения в нем представлений и сериализаторов:

$ python manage.py startapp authentication

Добавим ‘authentication’ в наш INSTALLED_APPS (в django_angular_token_auth/settings.py like so):

INSTALLED_APPS = (
	...,
	'rest_framework',
	'authentication',
)

Как привило после создания приложения нужно выполнить миграции, для создания моделей в БД. Но мы не будем создавать собственные модели, поэтому об этом не нужно беспокоиться.

Сторонние пакеты

Также доступны следующие сторонние пакеты.

Схема миграции

Приложение rest_framework.authtoken включает как Джанго миграцию, так и South миграцию которые создадут таблицу с токенами.

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

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

pip install django-oauth-toolkit

Добавьте пакет в свой INSTALLED_APPS и измените настройки вашего REST framework.

Дополнительные сведения см. в документации Django REST framework – Начало работы.

Шаблоны

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

Создайте файл с именем templates/index.html и добавьте следующий код в него:

В дальнейшем мы добавим некоторый angular код в данный файл.

Похожее:  Authentication using Python requests - GeeksforGeeks

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *