Как реализовать аутентификацию по токену с помощью Django REST Framework
В этом руководстве вы узнаете, как реализовать аутентификацию на основе токенов с помощью Django REST Framework (DRF). Аутентификация на основе токенов работает путем обмена имени пользователя и пароля на токен, который будет использоваться во всех последующих запросах для идентификации пользователя на стороне сервера.
Специфика обработки аутентификации на стороне клиента зависит от технологии/языка/фреймворка, с которым вы работаете. Клиент может быть мобильным приложением, использующим iOS или Android. Это может быть настольное приложение с использованием Python или C++. Это может быть веб-приложение на PHP или Ruby.
Но как только вы поймете общий процесс, вам будет легче найти необходимые ресурсы и документацию для вашего конкретного случая использования.
Аутентификация по токену подходит для клиент-серверных приложений, где токен безопасно хранится. Вы никогда не должны раскрывать свой токен, так как это (в некотором роде) эквивалентно передаче своего имени пользователя и пароля.
Оглавление
- Установка проекта REST API (Если вы уже знаете, как начать проект DRF, вы можете пропустить это)
- Внедрение аутентификации по токену
- Пользователь, запрашивающий токен
- Выводы
Установка проекта REST API
Итак, давайте начнем с самого начала. Установите Django и DRF:
pip install django
pip install djangorestframework
Создайте новый проект Django:
django-admin.py startproject myapi .
Перейдите в папку myapi:
cd myapi
Запустите новое приложение. Я назову свое приложение core:
django-admin.py startapp core
Вот как должна выглядеть структура вашего проекта:
myapi/
 |-- core/
 |    |-- migrations/
 |    |-- __init__.py
 |    |-- admin.py
 |    |-- apps.py
 |    |-- models.py
 |    |-- tests.py
 |    +-- views.py
 |-- __init__.py
 |-- settings.py
 |-- urls.py
 +-- wsgi.py
manage.py
Добавьте приложение core (которое вы создали) и приложение rest_framework (которое вы установили) в INSTALLED_APPS, внутри модуля settings.py:
myapi/settings.py
INSTALLED_APPS = [
    # Django Apps
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Third-Party Apps
    'rest_framework',
    # Local Apps (Your project's apps)
    'myapi.core',
]
Вернитесь в корень проекта (в папку, где находится скрипт manage.py) и перенесите базу данных:
python manage.py migrate
Давайте создадим наше первое представление API просто для проверки:
myapi/core/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
class HelloView(APIView):
    def get(self, request):
        content = {'message': 'Hello, World!'}
        return Response(content)
Теперь зарегистрируйте путь в модуле urls.py:
myapi/urls.py
from django.urls import path
from myapi.core import views
urlpatterns = [
    path('hello/', views.HelloView.as_view(), name='hello'),
]
Итак, теперь у нас есть API с одной конечной точкой /hello/, к которой мы можем выполнять GET запросы. Мы можем использовать браузер для потребления этой конечной точки, просто обратившись к URL http://127.0.0.1:8000/hello/:

Мы также можем попросить получить ответ в виде простых данных JSON, передав параметр format в строке запроса, как http://127.0.0.1:8000/hello/?format=json:

Оба метода подходят для опробования DRF API, но иногда инструмент командной строки более удобен, так как мы можем легче играть с заголовками запросов. Вы можете использовать cURL, который широко доступен во всех основных дистрибутивах Linux/macOS:
curl http://127.0.0.1:8000/hello/

Но обычно я предпочитаю использовать HTTPie, который является довольно удивительным инструментом командной строки Python:
http http://127.0.0.1:8000/hello/

Теперь давайте защитим эту конечную точку API, чтобы мы могли реализовать аутентификацию с помощью токенов:
myapi/core/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated  # <-- Here
class HelloView(APIView):
    permission_classes = (IsAuthenticated,)             # <-- And here
    def get(self, request):
        content = {'message': 'Hello, World!'}
        return Response(content)
Попробуйте снова получить доступ к конечной точке API:
http http://127.0.0.1:8000/hello/

Теперь мы получаем ошибку HTTP 403 Forbidden. Теперь давайте реализуем аутентификацию токена, чтобы мы могли получить доступ к этой конечной точке.
Внедрение аутентификации по токену
Нам нужно добавить две части информации в наш модуль settings.py. Сначала включите rest_framework.authtoken в ваш INSTALLED_APPS и включите TokenAuthentication в REST_FRAMEWORK:
myapi/settings.py
INSTALLED_APPS = [
    # Django Apps
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Third-Party Apps
    'rest_framework',
    'rest_framework.authtoken',  # <-- Here
    # Local Apps (Your project's apps)
    'myapi.core',
]
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',  # <-- And here
    ],
}
Переместите базу данных для создания таблицы, в которой будут храниться маркеры аутентификации:
python manage.py migrate

Теперь нам нужна учетная запись пользователя. Давайте просто создадим ее, используя утилиту командной строки manage.py:
python manage.py createsuperuser --username vitor --email vitor@example.com
Самый простой способ сгенерировать токен, только для целей тестирования, это снова использовать утилиту командной строки:
python manage.py drf_create_token vitor

Эту часть информации, случайную строку 9054f7aa9305e012b3c2300408c3dfdf390fcddf мы будем использовать для аутентификации.
Но теперь, когда у нас есть TokenAuthentication на месте, давайте попробуем сделать еще один запрос к нашей конечной точке /hello/:
http http://127.0.0.1:8000/hello/

Обратите внимание, как наш API теперь предоставляет клиенту дополнительную информацию о требуемом методе аутентификации.
Наконец, давайте используем наш токен!
http http://127.0.0.1:8000/hello/ 'Authorization: Token 9054f7aa9305e012b3c2300408c3dfdf390fcddf'

И это практически все. Впредь во всех последующих запросах вы должны включать заголовок Authorization: Token 9054f7aa9305e012b3c2300408c3dfdf390fcddf.
Форматирование выглядит странно и обычно вызывает недоумение, как установить этот заголовок. Это зависит от клиента и от того, как установить заголовок запроса HTTP.
Например, если бы мы использовали cURL, то команда была бы примерно такой:
curl http://127.0.0.1:8000/hello/ -H 'Authorization: Token 9054f7aa9305e012b3c2300408c3dfdf390fcddf'
Или если это был вызов Python requests:
import requests
url = 'http://127.0.0.1:8000/hello/'
headers = {'Authorization': 'Token 9054f7aa9305e012b3c2300408c3dfdf390fcddf'}
r = requests.get(url, headers=headers)
Однако, если бы мы использовали Angular, вы могли бы реализовать HttpInterceptor и установить заголовок:
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const user = JSON.parse(localStorage.getItem('user'));
    if (user && user.token) {
      request = request.clone({
        setHeaders: {
          Authorization: `Token ${user.accessToken}`
        }
      });
    }
    return next.handle(request);
  }
}
Пользователь запрашивает токен
DRF предоставляет конечную точку для пользователей, чтобы запросить маркер аутентификации, используя их имя пользователя и пароль.
Включите следующий маршрут в модуль urls.py:
myapi/urls.py
from django.urls import path
from rest_framework.authtoken.views import obtain_auth_token  # <-- Here
from myapi.core import views
urlpatterns = [
    path('hello/', views.HelloView.as_view(), name='hello'),
    path('api-token-auth/', obtain_auth_token, name='api_token_auth'),  # <-- And here
]
Итак, теперь у нас есть совершенно новая конечная точка API, которая называется /api-token-auth/. Давайте сначала проверим его:
http http://127.0.0.1:8000/api-token-auth/

Он не обрабатывает GET-запросы. По сути это просто представление для получения POST запроса с именем пользователя и паролем.
Попробуем еще раз:
http post http://127.0.0.1:8000/api-token-auth/ username=vitor password=123

В теле ответа находится токен, связанный с этим конкретным пользователем. После этого момента вы храните этот токен и применяете его к будущим запросам.
Тогда, опять же, способ выполнения POST-запроса к API зависит от используемого языка/фреймворка.
Если бы это был клиент Angular, вы могли бы хранить токен в localStorage, если бы это было приложение Desktop CLI, вы могли бы хранить в текстовом файле в домашнем каталоге пользователя в файле dot.
Выводы
Надеемся, что это руководство дало некоторое представление о том, как работает аутентификация с помощью токенов. Я постараюсь продолжить это руководство, предоставив несколько конкретных примеров приложений Angular, приложений командной строки и веб-клиентов.
Важно отметить, что реализация Token по умолчанию имеет некоторые ограничения, такие как только один токен на пользователя, нет встроенного способа установить дату истечения срока действия токена.
Вернуться на верх