Токен — це унікальний ключ, який використовується для ідентифікації користувача при роботі з API. На відміну від класичних методів аутентифікації, де користувач вводить логін і пароль для кожного запиту, токен використовується для одноразової аутентифікації: користувач вводить свої дані один раз, отримує токен, а потім включає його в кожен запит до сервера.
Приблизно це виглядає так:
- Користувач надсилає свої облікові дані (логін і пароль) на сервер.
- Сервер перевіряє їх правильність і повертає унікальний токен.
- Користувач надсилає цей токен у кожному наступному запиті, і сервер ідентифікує його за цим токеном.
Якщо провести аналогію, то токен можна порівняти з електронним пропуском в офіс (або, для програмістів, з бейджиком для кавомашини): отримав його один раз, і поки він дійсний, можеш спокійно проходити через турнікет/брати каву.
Чому токени такі популярні?
Давайте виділимо кілька ключових переваг токенів:
- Сесії не потрібні: на відміну від сесійної аутентифікації, токени дозволяють не зберігати стан на сервері. Сервер "не пам'ятає" користувача, він впізнає його за токеном.
- Простота масштабування: токени ідеально підходять для розподілених систем. Сервери можуть бути налаштовані незалежно один від одного, оскільки вся інформація про користувача "міститься" в переданому токені.
- Безпека: токени можна зробити одноразовими, задати час їх дії і додати шари шифрування. Це робить їх менш вразливими до атак, таких як крадіжка сесій.
- Універсальність: токени можна використовувати як для 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": "Невірні облікові дані"}, status=status.HTTP_400_BAD_REQUEST)
Цей код:
- Перевіряє облікові дані користувача.
- Якщо користувача знайдено, видаляє старий токен (якщо був).
- Створює новий токен із встановленим часом життя.
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("Невірний токен")
if not token.is_valid():
raise AuthenticationFailed("Термін дії токена закінчився")
return (token.user, token)
Тепер цей клас можна додати в налаштування REST_FRAMEWORK для використання в проєкті:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'myapp.authentication.TokenAuthentication',
],
}
Підсумки
Сьогодні ви познайомилися з концепцією токенів, їх основними перевагами та прикладами використання. Токени — важливий інструмент для безпечної та масштабованої аутентифікації у веб-застосунках. На наступному занятті ми зануримося в тему JSON Web Tokens (JWT) і дізнаємося, як вони пов'язані з API та токенами.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ