Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
JWT (JSON Web Token)
JWT — это компактный, стателесс способ представления информации между сторонами в виде JSON объекта. Используется для безопасной передачи данных, особенно для аутентификации и авторизации в веб-приложениях.
Структура JWT
JWT состоит из трех частей, разделенных точками:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Часть 1: Header (Заголовок)
Укодируется в Base64, содержит тип токена и алгоритм подписи:
{
"alg": "HS256", // Алгоритм подписи
"typ": "JWT" // Тип токена
}
Часть 2: Payload (Полезная нагрузка)
Укодируется в Base64, содержит claims (утверждения) — данные о пользователе:
{
"sub": "1234567890", // Subject (ID пользователя)
"name": "John Doe", // Имя
"email": "john@example.com",
"iat": 1516239022, // Issued At (когда выдан)
"exp": 1516242622 // Expiration (когда истекает)
}
Часть 3: Signature (Подпись)
Криптографическая подпись первых двух частей с секретным ключом:
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Как работает JWT
import jwt
from datetime import datetime, timedelta, timezone
# 1️⃣ СОЗДАНИЕ JWT
def create_jwt_token(user_id: int, email: str, secret_key: str) -> str:
"""Создать JWT токен."""
payload = {
'user_id': user_id,
'email': email,
'iat': datetime.now(timezone.utc), # Issued at
'exp': datetime.now(timezone.utc) + timedelta(hours=24) # Expires in 24 hours
}
token = jwt.encode(
payload,
secret_key,
algorithm='HS256'
)
return token
# Использование
token = create_jwt_token(123, 'john@example.com', 'my-secret-key')
print(token)
# eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsImVtYWlsIjoiam9obkBleGFtcGxlLmNvbSIsImlhdCI6MTY0MTc5MjEwMSwiZXhwIjoxNjQxODc4NTAxfQ...
# 2️⃣ ПРОВЕРКА И ДЕКОДИРОВАНИЕ JWT
def verify_jwt_token(token: str, secret_key: str) -> dict:
"""Проверить и декодировать JWT токен."""
try:
payload = jwt.decode(
token,
secret_key,
algorithms=['HS256']
)
return payload
except jwt.ExpiredSignatureError:
raise ValueError("Токен истек")
except jwt.InvalidTokenError:
raise ValueError("Недействительный токен")
# Использование
try:
payload = verify_jwt_token(token, 'my-secret-key')
print(payload) # {'user_id': 123, 'email': 'john@example.com', ...}
except ValueError as e:
print(f"Ошибка: {e}")
JWT в FastAPI
from fastapi import FastAPI, Depends, HTTPException
from fastapi.security import HTTPBearer, HTTPAuthCredentials
from datetime import datetime, timedelta, timezone
import jwt
app = FastAPI()
security = HTTPBearer()
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
# Модель пользователя
class User:
def __init__(self, id: int, email: str):
self.id = id
self.email = email
def create_access_token(user_id: int, email: str) -> str:
"""Создать access token."""
payload = {
'user_id': user_id,
'email': email,
'type': 'access',
'iat': datetime.now(timezone.utc),
'exp': datetime.now(timezone.utc) + timedelta(hours=1)
}
return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
def create_refresh_token(user_id: int) -> str:
"""Создать refresh token (долгоживущий)."""
payload = {
'user_id': user_id,
'type': 'refresh',
'iat': datetime.now(timezone.utc),
'exp': datetime.now(timezone.utc) + timedelta(days=7)
}
return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
def get_current_user(credentials: HTTPAuthCredentials = Depends(security)) -> User:
"""Получить текущего пользователя из JWT."""
token = credentials.credentials
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
user_id = payload.get('user_id')
email = payload.get('email')
if user_id is None:
raise HTTPException(status_code=401, detail="Invalid token")
return User(user_id, email)
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail="Token expired")
except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="Invalid token")
# Эндпоинты
@app.post("/login")
async def login(email: str, password: str):
"""Вход и получение токена."""
# Проверяем email и пароль
if email == "john@example.com" and password == "password123":
access_token = create_access_token(123, email)
refresh_token = create_refresh_token(123)
return {
"access_token": access_token,
"refresh_token": refresh_token,
"token_type": "bearer"
}
raise HTTPException(status_code=401, detail="Invalid credentials")
@app.get("/me")
async def get_me(user: User = Depends(get_current_user)):
"""Получить информацию о текущем пользователе."""
return {"id": user.id, "email": user.email}
@app.post("/refresh")
async def refresh_token(credentials: HTTPAuthCredentials = Depends(security)):
"""Обновить access token используя refresh token."""
token = credentials.credentials
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
if payload.get('type') != 'refresh':
raise HTTPException(status_code=401, detail="Invalid token type")
user_id = payload.get('user_id')
email = payload.get('email', f"user_{user_id}@example.com")
new_access_token = create_access_token(user_id, email)
return {"access_token": new_access_token, "token_type": "bearer"}
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail="Refresh token expired")
except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="Invalid token")
Плюсы JWT
# 1️⃣ Стателесс — сервер не хранит сессии
user_data = jwt.decode(token, SECRET_KEY) # Можно восстановить в любой момент
# 2️⃣ Масштабируемость — работает в микросервисах
# Сервис А создает токен
token = create_access_token(123, 'john@example.com')
# Сервис B проверяет токен с тем же secret key
# 3️⃣ Мобильные приложения — передается в заголовке
# Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# 4️⃣ CORS friendly — не требует cookies
# 5️⃣ Содержит все необходимые данные
payload = jwt.decode(token, SECRET_KEY)
user_id = payload['user_id']
scopes = payload.get('scopes', []) # Права доступа
Минусы JWT
# 1️⃣ Невозможно отозвать токен до истечения
# Токен выдан на 24 часа, но пользователь сменил пароль
# Старый токен остается действительным
# Решение: использовать blacklist
blacklist = set() # Множество отозванных токенов
def logout(token: str):
"""Отозвать токен."""
payload = jwt.decode(token, SECRET_KEY)
blacklist.add(token)
def get_current_user(token: str):
if token in blacklist:
raise HTTPException(status_code=401, detail="Token revoked")
# ...
# 2️⃣ Токены могут быть украдены (XSS)
# Хранить в localStorage небезопасно
# Решение: httpOnly cookies + CSRF protection
# 3️⃣ Размер токена может быть большим
# Много claims = большой токен
# Решается ограничением claims
# 4️⃣ Токен не может быть обновлен
# Если нужно изменить claims, требуется новый токен
Рекомендуемые практики
import os
from datetime import datetime, timedelta, timezone
class JWTConfig:
"""Конфигурация JWT."""
SECRET_KEY = os.getenv('JWT_SECRET_KEY')
ALGORITHM = 'HS256'
ACCESS_TOKEN_EXPIRE_MINUTES = 15 # Короткоживущий access token
REFRESH_TOKEN_EXPIRE_DAYS = 7 # Долгоживущий refresh token
@staticmethod
def create_access_token(data: dict) -> str:
"""Создать access token (15 минут)."""
to_encode = data.copy()
expire = datetime.now(timezone.utc) + timedelta(
minutes=JWTConfig.ACCESS_TOKEN_EXPIRE_MINUTES
)
to_encode.update({"exp": expire, "type": "access"})
return jwt.encode(
to_encode,
JWTConfig.SECRET_KEY,
algorithm=JWTConfig.ALGORITHM
)
@staticmethod
def create_refresh_token(user_id: int) -> str:
"""Создать refresh token (7 дней)."""
to_encode = {'user_id': user_id}
expire = datetime.now(timezone.utc) + timedelta(
days=JWTConfig.REFRESH_TOKEN_EXPIRE_DAYS
)
to_encode.update({"exp": expire, "type": "refresh"})
return jwt.encode(
to_encode,
JWTConfig.SECRET_KEY,
algorithm=JWTConfig.ALGORITHM
)
@staticmethod
def verify_token(token: str) -> dict:
"""Проверить и декодировать токен."""
try:
payload = jwt.decode(
token,
JWTConfig.SECRET_KEY,
algorithms=[JWTConfig.ALGORITHM]
)
return payload
except jwt.ExpiredSignatureError:
raise ValueError("Token expired")
except jwt.InvalidTokenError:
raise ValueError("Invalid token")
# Использование
access_token = JWTConfig.create_access_token({'user_id': 123, 'email': 'john@example.com'})
refresh_token = JWTConfig.create_refresh_token(123)
payload = JWTConfig.verify_token(access_token)
JWT vs Session
| Свойство | JWT | Session |
|---|---|---|
| Хранилище | Клиент | Сервер |
| Масштабируемость | Хорошая | Нужна общая БД |
| Безопасность | Подпись | Сессионный ID |
| Отзыв | Сложный | Простой |
| Размер | Больше | Маленький |
| CORS | Хорошо | Требует cookies |
Вывод: JWT — это мощный механизм аутентификации для современных приложений, особенно для API и мобильных приложений. Главное — правильно управлять временем жизни токенов и использовать комбинацию access + refresh токенов.