Делаем авторизацию по JWT-токенам

Курс по Django: https://stepik.org/a/183363

После того, как мы познакомились с принципом авторизации с помощью JWT-токенов, давайте реализуем их в нашем учебном проекте. На странице официального ресурса по Django REST Framework:

https://www.django-rest-framework.org/api-guide/authentication/#json-web-token-authentication

сказано, что для этого можно воспользоваться библиотекой «Simple JWT».

Почему именно эта библиотека? Во-первых, она довольно популярна и вы вероятнее всего именно с ней и столкнетесь. А, во-вторых, другая популярная библиотека Djoser может работать в связке с «Simple JWT».

Перейдем на сайт этой библиотеки и откроем раздел «Getting started»:

https://django-rest-framework-simplejwt.readthedocs.io/en/latest/getting_started.html

Здесь подробно описывается процесс установки этого пакета. Я прямо им и буду руководствоваться. Вначале нам нужно установить этот пакет командой:

pip install djangorestframework-simplejwt

Затем, в файле settings.py в словаре REST_FRAMEWORK прописать возможность авторизации через JWT-токены:

REST_FRAMEWORK = {
    ...
 
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework_simplejwt.authentication.JWTAuthentication',
        ...
    ]
}

После этого в файле drfsite/urls.py импортируем три класса представлений для создания, обновления и проверки подписи JWT-токенов:

from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView, TokenVerifyView

Далее, в коллекцию urlpatterns добавим три маршрута (берем из документации):

urlpatterns = [
    ...
    path('api/v1/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/v1/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    path('api/v1/token/verify/', TokenVerifyView.as_view(), name='token_verify'),
]

Затем из раздела «Settings»:

https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html

копируем словарь SIMPLE_JWT и вставляем в файл drfsite/settings.py. (Подправляем там SECRET_KEY и импортируем функцию timedelta).

В принципе это все, мы подключили авторизацию через JWT-токены к нашему проекту. Но, прежде чем протестировать их работу, давайте внимательно посмотрим на содержимое словаря SIMPLE_JWT. Здесь перечислено множество ключей. Их подробное описание дано на странице документации. Но о некоторых из них следует сказать пару слов. Первые две строчки:

    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),

определяют интервал времени активности выданного access_token и интервал времени обновления refresh_token.

Далее, ключи:

    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,

указывают алгоритм шифрования для формирования подписи (HS256) и используемый для этого секретный ключ.

Следующие ключи:

    'AUTH_HEADER_TYPES': ('Bearer',),
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',

определяют заголовок перед токеном в заголовке запроса, поле, в котором будет передаваться токен, и что в JWT-токене будет сохраняться информация об идентификаторе пользователя в виде ключа user_id.

Еще три ключа:

    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
    'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),

настраивают параметры для sliding-токенов. Это еще одна идея использования JWT-токенов, о которой мы не говорили. Но я оставлю это «за кадром». Здесь мы определяем те же значения времени истечения, что и для access_token и refresh_token.

(Не забываем в классе WomenAPIUpdate поставить комментарий у атрибута authentication_classes).

С основными настройками разобрались и пора запускать тестовый веб-сервер. Перейдем на страницу:

http://127.0.0.1:8000/api/v1/token/

Введем:

username: seconduser
password: fghgfhhuser123

и нам были отправлены access_token и refresh_token.

Я скопирую содержимое access_token, перейду на страницу:

https://jwt.io

где мы можем раскодировать наш JWT-токен и посмотреть на его содержимое:

Здесь имеется заголовок (header) и полезные данные (payload). В данных указан тип токена, время жизни, метка jti для работы с токеном в БД и идентификатор пользователя.

То есть, когда токен будет отправлен на сайт, то сайт «поймет» какой пользователь запрашивает доступ и, соответственно, ему он и будет предоставлен.

Давайте выполним отправку JWT-токена для доступа к приватной странице нашего сайта:

http://127.0.0.1:8000/api/v1/women/9/

Для этого я симитирую передачу запроса от стороннего приложения через программу Postman. Во вкладке укажу URL-адрес страницы, тип запроса будет GET (получить страницу), а на вкладке «Headers» пропишу ключ «Authorization» со значением:

Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjM4Njk0NDcwLCJqdGkiOiIyZDNlMWFmNGU4Zjg0ZmNkODhlNmViMjU1MTY5ZDJhYyIsInVzZXJfaWQiOjV9.fuLiYMJJ9MeMDIoQNJGRUHPbmrn9rcpCIQiFvuQCqJk

Мы здесь должны указать мету JWT-токена, которая записана в настройках SIMPLE_JWT, а затем, сам access_token. Отправляем запрос и получаем приватную информацию. Если отключить в заголовке поле «Authorization», то сервер вернет JSON-строку:

{"detail":"Учетные данные не были предоставлены."}

То есть, у нас действительно работает алгоритм авторизации на основе JWT-токенов.

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

Курс по Django: https://stepik.org/a/183363