JavaRush /Курсы /Модуль 3: Django /Введение в систему токенов

Введение в систему токенов

Модуль 3: Django
18 уровень , 1 лекция
Открыта

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

Приблизительно это выглядит так:

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

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

Почему токены так популярны?

Давайте выделим несколько ключевых преимуществ токенов:

  1. Сессии не нужны: в отличие от сессионной аутентификации, токены позволяют не хранить состояние на сервере. Сервер "не помнит" пользователя, он узнаёт его по токену.
  2. Простота масштабирования: токены отлично подходят для распределённых систем. Серверы могут быть настроены независимо друг от друга, так как вся информация о пользователе "содержится" в передаваемом токене.
  3. Безопасность: токены можно сделать одноразовыми, задать время их действия и добавить слои шифрования. Это делает их менее уязвимыми для атак, таких как кража сессий.
  4. Универсальность: токены можно использовать как для API, так и для мобильных приложений, десктопных программ и других клиентов.

Как токены работают в контексте DRF?

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

Как это выглядит "под капотом":

  • Когда пользователь логинится, он получает токен, связанный с его учётной записью. Этот токен сохраняется в базе данных.
  • Во всех последующих запросах пользователь отправляет токен в HTTP-заголовке Authorization.
  • Сервер проверяет токен на подлинность и, если он действителен, выполняет запрос.

Пример заголовка:

Authorization: Token abc123...

Виды токенов

  • Постоянные токены. Этот тип токенов создаётся один раз и действует до тех пор, пока не будет отозван вручную. Это хорошо работает в простых сценариях, но может быть небезопасно, если токен случайно "утечёт".

  • Одноразовые токены. Такой токен можно использовать только один раз, после чего он становится недействительным. Это повышает уровень безопасности, но требует больше усилий для реализации.

  • Временные токены. У таких токенов есть время жизни (например, 30 минут). Это делает их подходящими для защиты данных, но может требовать дополнительных механизмов обновления токенов.

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

Попробуем применить концепцию токенов на практике.

1. Создание модели токенов

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

from django.db import models
from django.contrib.auth.models import User
from django.utils.timezone import now
import uuid

class Token(models.Model):
    key = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    expires_at = models.DateTimeField()

    def is_valid(self):
        return now() < self.expires_at

Этот код создаёт модель токенов с полями:

  • key — уникальный идентификатор токена.
  • user — связанный пользователь, для которого создаётся токен.
  • created_at — время создания токена.
  • expires_at — время, до которого токен действителен.

Метод is_valid() проверяет, не истёк ли срок действия токена.

2. Создание токена при входе пользователя

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

from django.utils.timezone import now, timedelta
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.contrib.auth import authenticate
from .models import Token

class ObtainAuthToken(APIView):

    def post(self, request):
        username = request.data.get("username")
        password = request.data.get("password")

        user = authenticate(username=username, password=password)
        if user:
            # Удаляем старый токен (если есть)
            Token.objects.filter(user=user).delete()

            # Создаём новый токен
            token = Token.objects.create(
                user=user,
                expires_at=now() + timedelta(hours=1)  # токен действителен 1 час
            )
            return Response({"token": token.key}, status=status.HTTP_200_OK)
        return Response({"error": "Invalid credentials"}, status=status.HTTP_400_BAD_REQUEST)

Этот код:

  1. Проверяет учетные данные пользователя.
  2. Если пользователь найден, удаляет старый токен (если был).
  3. Создаёт новый токен с установленным временем жизни.

3. Использование токена в запросах

Каждый запрос к API успешно аутентифицированного пользователя должен включать токен в заголовке Authorization.

Вот как это выглядит, если вы отправляете запрос с помощью cURL:

curl -X GET http://127.0.0.1:8000/api/protected-resource/ \
-H "Authorization: Token <ваш-токен>"

4. Проверка токена при запросах

Для проверки токена можно написать свой класс аутентификации.

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from .models import Token

class TokenAuthentication(BaseAuthentication):

    def authenticate(self, request):
        auth_header = request.headers.get("Authorization")
        if not auth_header or not auth_header.startswith("Token "):
            return None

        key = auth_header.split(" ")[1]
        try:
            token = Token.objects.get(key=key)
        except Token.DoesNotExist:
            raise AuthenticationFailed("Invalid token")

        if not token.is_valid():
            raise AuthenticationFailed("Token has expired")

        return (token.user, token)

Теперь этот класс можно добавить в настройки REST_FRAMEWORK для использования в проекте:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'myapp.authentication.TokenAuthentication',
    ],
}

Итоги

Сегодня вы познакомились с концепцией токенов, их основными преимуществами и примерами использования. Токены — важный инструмент для безопасной и масштабируемой аутентификации в веб-приложениях. На следующем занятии мы погрузимся в тему JSON Web Tokens (JWT) и узнаем, как они связаны с API и токенами.

1
Задача
Модуль 3: Django, 18 уровень, 1 лекция
Недоступна
Установка DRF и настройка аутентификации
Установка DRF и настройка аутентификации
1
Задача
Модуль 3: Django, 18 уровень, 1 лекция
Недоступна
Создание эндпоинтов для получения токенов
Создание эндпоинтов для получения токенов
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ