JWT — це JSON Web Token, компактний і безпечний спосіб передачі інформації між двома сторонами у вигляді токена. Тут ключове слово — компактний. JWT — це всього лиш стрічка, яка містить інформацію (payload), закодовану в форматі JSON, з підписом для верифікації.
Структура JWT
JWT складається з трьох частин, розділених крапками:
- Header (заголовок) — інформація про тип токена (JWT) та алгоритм підпису, наприклад, HMAC або RSA.
- Payload (корисне навантаження) — власне дані, які ви передаєте: наприклад, ідентифікатор користувача, роль, строк дії токена.
- Signature (підпис) — цифровий підпис, який використовується для перевірки цілісності даних.
Приклад JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoiYWRtaW4iLCJleHBpcnkiOjE2NzI4MTU2MDB9.2bc89a2c5e2c0f3bea865d3c8b4d9e3c8123e5f5
Розшифрувавши це, ми отримаємо:
- Header (base64):
{ "alg": "HS256", "typ": "JWT" } - Payload (base64):
{ "user_id": 1, "role": "admin", "expiry": 1672815600 } - Signature (hex):
2bc89a2c5e2c0f3bea865d3c8b4d9e3c8123e5f5
Ця структура дозволяє вам безпечно передавати дані та перевіряти їх автентичність на стороні сервера.
Чому JWT?
Мабуть, ви питаєтесь: "Чому саме JWT? Чому не сесії або інші форми токенів?" Ось кілька причин:
- JWT самодостатній: він містить всю інформацію про користувача, не вимагаючи звернення до бази даних.
- Він легко масштабується: ви можете використовувати його в розподілених архітектурах.
- JWT працює з коробки з більшістю сучасних технологій.
- Токен підписаний, що запобігає його підробці (якщо використовується хороший секретний ключ).
Генерація JWT у FastAPI
FastAPI — це крута штука, і завдяки бібліотеці PyJWT робота з JWT стає ще простішою.
Встановлення бібліотеки
Для роботи з JWT встановимо бібліотеку PyJWT:
pip install pyjwt
Тепер створимо код для генерації токенів.
Генерація токенів
Ось приклад функції для створення JWT з використанням алгоритму HMAC SHA256:
from datetime import datetime, timedelta
from typing import Union
import jwt
# Секретний ключ для підпису токенів (тримайте його в секреті!)
SECRET_KEY = "super_secret_key_please_change_me"
ALGORITHM = "HS256"
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
"""
Створює JWT токен.
:param data: Корисне навантаження токена (наприклад, ідентифікатор користувача).
:param expires_delta: Час життя токена (опціонально).
:return: Рядок JWT.
"""
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15) # токен дійсний 15 хвилин за замовчуванням
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
Як це працює?
- Ми додаємо поле
expдля вказання строку дії токена. - Корисне навантаження (
data) доповнюється інформацією про строк дії. - Потім ми підписуємо токен з використанням секретного ключа.
Приклад використання функції:
payload = {"user_id": 1, "role": "admin"}
access_token = create_access_token(data=payload, expires_delta=timedelta(hours=1))
print(access_token)
Отримаєте рядок вигляду:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoiYWRtaW4iLCJleHBpciI6MTY3MjgxNjAwMH0.T1wGbYFvEc2nOdfAqJ5CkpA0u2V2_q2BdV0Ysx8n3VU
Перевірка та декодування JWT
Після того як ваш сервер згенерував JWT, потрібно вміти його перевіряти.
Перевірка токенів з PyJWT
Для перевірки токенів використовується функція jwt.decode. Ось приклад:
def verify_token(token: str):
"""
Перевіряє автентичність токена і повертає корисне навантаження.
:param token: JWT токен.
:return: Декодовані дані токена.
"""
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except jwt.ExpiredSignatureError:
raise Exception("Токен сплив!") # Обробка помилки закінчення строку дії
except jwt.InvalidTokenError:
raise Exception("Недійсний токен!") # Обробка інших помилок
Як це працює?
jwt.decode()перевіряє підпис токена.- Якщо токен сплив, викидається виключення
ExpiredSignatureError. - Для недійсних токенів викидається
InvalidTokenError.
Приклад використання:
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJyb2xlIjoiYWRtaW4iLCJleHBpciI6MTY3MjgxNjAwMH0.T1wGbYFvEc2nOdfAqJ5CkpA0u2V2_q2BdV0Ysx8n3VU"
try:
payload = verify_token(token)
print(payload)
except Exception as e:
print(str(e))
Якщо все нормально, побачите корисне навантаження:
{'user_id': 1, 'role': 'admin', 'exp': 1672816000}
Інтеграція у FastAPI
Тепер об'єднаємо все це в FastAPI-застосунку.
Приклад ендпоінту для створення токена
from fastapi import FastAPI, Depends
from pydantic import BaseModel
app = FastAPI()
class TokenData(BaseModel):
username: str
@app.post("/token")
async def generate_token(data: TokenData):
"""
Створює JWT токен для користувача.
"""
payload = {"username": data.username}
access_token = create_access_token(data=payload)
return {"access_token": access_token, "token_type": "bearer"}
Приклад ендпоінту для перевірки токена
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@app.get("/protected")
async def protected_route(token: str = Depends(oauth2_scheme)):
"""
Приклад захищеного маршруту.
"""
try:
payload = verify_token(token)
return {"message": f"Ласкаво просимо, {payload['username']}!"}
except Exception as e:
return {"error": str(e)}
Практичне застосування
На практиці JWT використовують для:
- Захисту ендпоінтів: тільки користувачі з валідними токенами можуть отримати доступ.
- Підтвердження автентичності: токен містить інформацію тільки для одного користувача.
- Мікросервісів: JWT дозволяє передавати дані між сервісами.
Однак пам'ятайте: безпека понад усе! Тримайте секретні ключі в секреті і використовуйте короткі строки дії токенів.
Офіційна документація PyJWT: https://pyjwt.readthedocs.io/
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ