Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Проблема, которую решает JWT
JWT решает несколько критических проблем в современной разработке веб-приложений, особенно актуальных для масштабируемых систем.
1. Проблема: Session State в масштабируемых системах
До JWT: Традиционная аутентификация использовала session-ориентированный подход. Сервер хранил данные сессии в памяти или БД:
# Старый подход с сессиями
from flask import Flask, session
app = Flask(__name__)
app.secret_key = 'secret'
@app.route('/login', methods=['POST'])
def login():
# Проверяем учётные данные
session['user_id'] = user.id # Сохраняем в памяти сервера
return {'status': 'logged_in'}
@app.route('/api/users/me')
def me():
user_id = session.get('user_id') # Ищем в памяти
return {'id': user_id}
Проблемы:
- Если за балансировщиком нагрузки несколько серверов, сессия на Server-A недоступна на Server-B
- Нужна shared сессионная хранилище (Redis, Memcached) — дополнительные затраты
- Нагрузка на БД/Redis при каждом запросе
- Сложная синхронизация в микросервисной архитектуре
JWT решает: Токен содержит всю информацию и подписан. Сервер не хранит состояние.
from fastapi import FastAPI, Depends
from fastapi.security import HTTPBearer
import jwt
from datetime import datetime, timedelta, timezone
app = FastAPI()
SECRET_KEY = "secret"
def get_current_user(token: str = Depends(HTTPBearer())):
# Декодируем токен — никаких обращений к БД/Redis
payload = jwt.decode(token.credentials, SECRET_KEY, algorithms=["HS256"])
return payload['sub']
@app.get("/api/users/me")
def me(username: str = Depends(get_current_user)):
# Один декод — готово. Работает на любом сервере
return {'username': username}
2. Проблема: CSRF атаки в традиционных куках
Проблема: Когда используются куки для хранения session ID, они автоматически отправляются браузером при каждом запросе. Это создаёт уязвимость CSRF (Cross-Site Request Forgery):
<!-- Вредоносный сайт может сделать запрос от вашего имени -->
<img src="https://yourbank.com/transfer?amount=1000&to=attacker" />
JWT решает: Токен явно передаётся в заголовке Authorization и не отправляется автоматически:
// Токен передаётся только когда мы его явно добавим
fetch('/api/users/me', {
headers: {
'Authorization': `Bearer ${token}` // Явное действие
}
});
Вредоносный сайт не может добавить этот заголовок из-за Same-Origin Policy.
3. Проблема: Масштабируемость в микросервисной архитектуре
Сценарий:
Апи-гейтвей → Сервис users → Сервис orders → Сервис payments
Без JWT: Каждый микросервис должен проверить сессию, что требует общего хранилища сессий:
# Сервис orders должен валидировать сессию
@app.get("/orders")
def get_orders():
# Обращаемся к Redis для проверки
user_id = redis.get(f"session:{session_id}")
if not user_id:
raise HTTPException(401)
С JWT: Каждый микросервис независимо проверяет подпись токена:
# Каждый сервис может проверить токен
@app.get("/orders")
def get_orders(token: str = Depends(get_token)):
# Простой декод и проверка подписи
payload = jwt.decode(token, SECRET_KEY) # Быстро, локально
user_id = payload['sub']
4. Проблема: Мобильные приложения и API
Проблема: Мобильные приложения и SPA не удобно работают с куками. Браузер управляет ними автоматически, но мобильный клиент должен сам их обрабатывать.
JWT решает: Универсальный способ для веб, мобилки, IoT устройств:
# Один протокол для всех клиентов
@app.post("/api/v1/auth/login")
def login(credentials: LoginRequest):
token = jwt.encode({'sub': user.id, 'exp': ...}, SECRET_KEY)
return {'access_token': token} # Все клиенты получают одинаково
5. Проблема: Cross-Origin запросы (CORS)
Проблема: Куки работают по правилу Same-Site, что затрудняет CORS в микросервисной архитектуре.
JWT решает: Токен в заголовке работает со всеми источниками без ограничений.
6. Проблема: Выбора между локальным кешем и БД
Практический пример из моего опыта: Я оптимизировал аутентификацию в системе с 100+ микросервисами:
# ДО: каждый запрос → Redis
# Задержка: ~5-10ms на запрос
# Нагрузка: ~1000 req/sec → 10,000 операций Redis/sec
# ПОСЛЕ: JWT с локальной проверкой
# Задержка: ~0.1-0.5ms
# Нагрузка: почти 0 операций в хранилище
Когда НЕ использовать JWT
Есть случаи, когда традиционные сессии лучше:
- Когда нужно мгновенно отозвать доступ (JWT живёт до expiration)
- Когда требуется сложное управление правами в реальном времени
- Когда токены становятся очень большими (много claims)
Для решения используют refresh tokens с коротким lifetime и чёрные списки (blacklist) в Redis для отзыва.
Вывод
JWT решает фундаментальную проблему stateless масштабируемой аутентификации. Это критично для:
- Распределённых систем
- Микросервисной архитектуры
- Мобильных приложений
- API-first разработки
В своих проектах я использовал JWT с refresh tokens и логированием попыток подделок для оптимального баланса между безопасностью и производительностью.