Вход и JWT access token
Уроки курсаВход и JWT access token
В прошлом уроке POST /api/users сохранил хеш Argon2 и вернул только id и email. Пароль нигде не попал в ответ. Теперь нужен следующий шаг: пользователь присылает email и пароль повторно, а сервер должен убедиться, что пароль верный, и выдать токен, с которым можно обращаться к защищённым маршрутам. Этот токен — JWT access token.
create_access_token: sub, срок exp и подпись HS256
Продолжайте тот же проект auth_demo. Добавьте строку в requirements.txt:
PyJWT==2.10.1
Переустановите зависимости:
pip install -r requirements.txt
Прежде чем запускать приложение, задайте SECRET_KEY в переменных окружения. Это не пароль, который придумывает человек, — это 32 случайных байта, закодированных в urlsafe-Base64. В bash:
export SECRET_KEY="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
В PowerShell:
$env:SECRET_KEY = python -c "import secrets; print(secrets.token_urlsafe(32))"
Значение генерируется один раз и остаётся постоянным на всё время жизни сервиса. Ключ не коммитится в репозиторий, не возвращается через /info и не меняется при каждом перезапуске. Если ключ сменился — все ранее выданные токены, подписанные старым ключом, станут непроверяемыми: новый ключ просто даст другую подпись, которая не совпадёт.
Новый файл app/tokens.py содержит единственную функцию:
from datetime import datetime, timedelta, timezone
import jwt
def create_access_token(token_subject: str, secret_key: str, expires_minutes: int = 30) -> str:
payload = {
"sub": token_subject,
"exp": datetime.now(timezone.utc) + timedelta(minutes=expires_minutes),
}
return jwt.encode(payload, secret_key, algorithm="HS256")
Функция принимает token_subject — это User.token_subject, постоянная случайная строка учётной записи, которую не нужно путать с email или числовым id. В sub кладут стабильный идентификатор, по которому сервер потом найдёт пользователя; email туда не помещают, потому что он может измениться.
exp — момент в UTC через 30 минут от текущего времени. PyJWT принимает объект datetime и сам преобразует его в Unix timestamp. Обратите внимание: exp фиксируется в момент выпуска токена. Это не означает, что токен автоматически отклоняется по истечении срока — принимающая сторона обязана явно проверить срок при каждом запросе.
Функция получает secret_key аргументом, а не обращается к get_settings напрямую. Это упрощает тестирование: в тестах можно передать любой ключ, не трогая окружение. В продакшн-коде ключ передаётся из get_settings — та же зависимость, что уже есть в проекте.
