Уявіть, що ви потрапили на закриту вечірку, куди пускають тільки за гарними золотими квитками. JWT — це саме той квиток, який дозволяє вам довести, що ви запрошені. Це компактний і самодостатній спосіб передачі інформації між сторонами у вигляді токена.
Структура JWT
JWT складається з трьох частин, розділених крапками:
- Header (заголовок) — містить метаінформацію про токен: тип токена (зазвичай
JWT) і алгоритм підпису (наприклад,HS256для HMAC абоRS256для RSA). - Payload (корисне навантаження) — містить дані (заявки або claims), такі як ідентифікатор користувача, роль і час закінчення дії токена.
- Signature (підпис) — гарантує цілісність токена. Він створюється на основі заголовка та payload з використанням секретного ключа або пари ключів (у випадку RSA).
Коли ви з'єднаєте три частини разом, отримаєте рядок вигляду:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoiYWRtaW4iLCJleHAiOjE2MzM4MTU4ODZ9.abc123signature
І так, виглядає як Wi‑Fi пароль вашої бабусі. Але це ваш ключ для доступу в систему.
Переваги JWT
Чому JWT такий популярний? Є кілька причин:
- Компактність: JWT — це просто рядок, який легко передається через URL, headers або навіть body запиту.
- Самодостатність: на відміну від традиційних сесій, JWT містить у собі всю необхідну інформацію, тому серверу не потрібно зберігати нічого про стан клієнта.
- Кросплатформність: будучи основаним на JSON, JWT легко інтегрується з будь-якими технологіями — будь то Python, JavaScript або навіть добрий старий PHP.
- Безпека: використовуючи підпис, JWT гарантує, що його вміст не було змінено після створення.
Як це працює?
Усе починається з аутентифікації користувача. Ось приблизний процес видання JWT:
- Користувач логіниться.
- Сервер генерує JWT, підписує його і відправляє назад.
- Клієнт зберігає токен, наприклад, в cookies або localStorage.
- При кожному запиті клієнт відправляє токен у заголовку Authorization (наприклад,
Bearer eyJhbGciOiJI...). - Сервер перевіряє підпис і витягує дані з токена.
Алгоритми підпису JWT
Підпис — ключовий механізм безпеки JWT, тому важливо розуміти, як він працює.
HMAC (наприклад, HS256)
Цей алгоритм використовує секретний ключ, який має бути відомий лише серверу. Приблизно як ваш улюблений рецепт млинців, який ви ніколи не розкажете сусідові.
Signature = HMAC_SHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
- Переваги: простота і легкість налаштування.
- Недоліки: у вас може бути лише один ключ, тож якщо його "злили", то біда.
RSA (наприклад, RS256)
У цьому випадку використовується пара ключів: приватний для створення підпису і публічний для його перевірки. Ваш підпис — як автограф: лише ви можете його поставити, але будь-хто може перевірити його достовірність (звісно, знаючи ваш стиль письма).
Signature = RSA_sign(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
private_key
)
- Переваги: високий рівень безпеки.
- Недоліки: налаштування інфраструктури ключів може бути складною.
Приклад використання JWT у FastAPI
Давайте трохи коду, бо розробники люблять код так само, як каву і меми про програмістів.
Спочатку встановимо бібліотеку для роботи з JWT:
pip install pyjwt
Тепер згенеруємо JWT.
Ось приклад створення JWT у FastAPI:
import jwt
from datetime import datetime, timedelta
SECRET_KEY = "your_secret_key" # Зберігайте секретний ключ у змінних оточення!
def create_jwt(data: dict):
expiration = datetime.utcnow() + timedelta(hours=1)
payload = data.copy()
payload.update({"exp": expiration})
return jwt.encode(payload, SECRET_KEY, algorithm="HS256")
Тепер при логіні ви можете повертати користувачу його JWT:
@app.post("/login")
async def login(username: str, password: str):
# Тут має бути логіка перевірки логіна і пароля
user = {"id": 1, "username": username}
token = create_jwt(user)
return {"access_token": token}
Перевіримо JWT при запиті:
def decode_jwt(token: str):
try:
decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
return decoded
except jwt.ExpiredSignatureError:
raise HTTPException(status_code=401, detail="Token has expired")
except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="Invalid token")
Використовуємо це в ендпоінті:
@app.get("/protected")
async def protected_route(token: str = Header(...)):
user_data = decode_jwt(token)
return {"message": f"Welcome, {user_data['username']}!"}
Корисні нюанси та типові помилки
- JWT можна підробити? Ні, якщо ваш секретний ключ дійсно секретний. Тому не зберігайте його в коді.
- Токен закінчився? Додайте
expу payload. Це допоможе уникнути використання старих токенів. - Де зберігати токен? Краще в
httpOnlyкуках. LocalStorage менш безпечний, бо вразливий до атак XSS. - JWT — не заміна для HTTPS. Щоб запобігти MITM-атакам, завжди використовуйте HTTPS.
Приклади реального застосування JWT
- Google, Facebook, GitHub. Майже всі великі сервіси використовують JWT для забезпечення безпеки.
- Мікросервісна архітектура. JWT чудово підходить для передачі статусу авторизації між сервісами.
- SPA (Single Page Applications). Це один із найкращих способів аутентифікації у сучасному фронтенді.
Тепер ви розумієте, що JWT — це не просто модне слово, а потужний інструмент для розробки безпечних API. У наступній лекції ми розберемо, як інтегрувати JWT у систему аутентифікації за допомогою FastAPI і реалізувати повноцінний захист ваших маршрутів.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ