Если вы пишете API на FastAPI, то очень быстро упираетесь в «обвязку» вокруг пользователей: регистрация, логин, сброс пароля, подтверждение почты, роли, хранение токенов, интеграция с БД. Всё это типовое, но легко сделать небезопасно или грязно. fastapi-users закрывает эту зону риска: даёт готовые роуты, менеджер пользователей и набор адаптеров, которые можно настроить под проект.

Сейчас библиотека находится в режиме maintenance mode: новых фич не добавляют, но поддерживают совместимость и выпускают обновления безопасности. Это важно для выбора стека: модуль стабилен и предсказуем, но не стоит ждать «революций».

Что такое fastapi-users и зачем он нужен

fastapi-users — это набор компонентов для управления пользователями в FastAPI:

  • готовые эндпоинты: register, login, logout, forgot-password, reset-password, verify;
  • механизмы аутентификации (JWT, cookies, OAuth через соцсети/провайдеров);
  • интеграции с разными слоями данных (SQLAlchemy, Beanie/Mongo, etc.);
  • расширяемый UserManager для бизнес-логики вокруг пользователей.

Главная идея: вы не изобретаете велосипед, а подключаете проверенное решение и настраиваете только то, что уникально для вашего приложения.

Архитектура модуля: из чего он состоит

У fastapi-users есть несколько ключевых уровней.

Модели и схемы пользователя

Библиотека ожидает Pydantic-схемы для:

  • чтения пользователя (UserRead);
  • создания (UserCreate);
  • обновления (UserUpdate).

Вы решаете, какие поля есть у пользователя (например, username, is_admin, telegram_id), а модуль заботится о валидации и сериализации.

User database adapter

Это слой доступа к данным. Вы выбираете реализацию под вашу БД (например, SQLAlchemy). Адаптер обеспечивает CRUD-операции, не привязывая остальную логику к конкретному ORM.

UserManager

Сюда вы вкладываете бизнес-правила: что делать после регистрации, как валидировать пароль, какие дополнительные проверки нужны. Он передаётся через dependency injection.

Authentication backend

Бэкенд определяет как пользователь логинится и как хранится сессия/токен:

  • JWT в заголовках,
  • cookie-сессии,
  • OAuth2-провайдеры (Google, GitHub, и т. п.).

Routers

Набор готовых роутов подключается к вашему приложению одной строкой. Это ускоряет старт проекта и снижает число ошибок в безопасности.

Быстрый старт: минимальная настройка (пример)

Ниже — укороченная версия рабочего примера с JWT и SQLAlchemy. Полный пример есть в доках.

Установка

pip install fastapi-users[sqlalchemy] uvicorn

Схемы

from pydantic import BaseModel, EmailStr
from fastapi_users import schemas

class UserRead(schemas.BaseUser[int]):
    pass

class UserCreate(schemas.BaseUserCreate):
    pass

class UserUpdate(schemas.BaseUserUpdate):
    pass

Модель SQLAlchemy и адаптер БД (сильно упрощено)

from fastapi_users_db_sqlalchemy import SQLAlchemyBaseUserTable, SQLAlchemyUserDatabase
from sqlalchemy.ext.asyncio import AsyncSession

class User(SQLAlchemyBaseUserTable[int]):
    pass

async def get_user_db(session: AsyncSession):
    yield SQLAlchemyUserDatabase(session, User)

Аутентификация и FastAPIUsers

from fastapi_users import FastAPIUsers
from fastapi_users.authentication import JWTStrategy, AuthenticationBackend, BearerTransport

bearer_transport = BearerTransport(tokenUrl="auth/jwt/login")

def get_jwt_strategy() -> JWTStrategy:
    return JWTStrategy(secret="CHANGE_ME", lifetime_seconds=3600)

auth_backend = AuthenticationBackend(
    name="jwt",
    transport=bearer_transport,
    get_strategy=get_jwt_strategy,
)

fastapi_users = FastAPIUsers(get_user_manager, [auth_backend])

Подключение роутов

app.include_router(
    fastapi_users.get_auth_router(auth_backend),
    prefix="/auth/jwt",
    tags=["auth"],
)

app.include_router(
    fastapi_users.get_register_router(UserRead, UserCreate),
    prefix="/auth",
    tags=["auth"],
)

app.include_router(
    fastapi_users.get_users_router(UserRead, UserUpdate),
    prefix="/users",
    tags=["users"],
)

На выходе вы получаете полный набор эндпоинтов с OpenAPI-документацией и безопасной реализацией базовых сценариев.

Кастомизация: где fastapi-users особенно полезен

Добавляем поля профиля

Хотите full_name и role? Добавьте их в SQLAlchemy-модель и Pydantic-схемы — и модуль автоматически начнёт их принимать/возвращать в нужных местах. Главное — не забыть про миграции.

Валидация пароля и post-hooks

В UserManager можно:

  • запретить слабые пароли,
  • не пускать корпоративные домены,
  • отправлять welcome-письмо после регистрации,
  • логировать события.

RBAC / роли

fastapi-users не навязывает систему ролей, но делает главное — даёт dependency current_user(). Дальше вы строите авторизацию как удобно:

current_active_user = fastapi_users.current_user(active=True)

@app.get("/admin")
async def admin_panel(user=Depends(current_active_user)):
    if not user.is_admin:
        raise HTTPException(status_code=403)
    return {"ok": True}

Плюсы и минусы

Что хорошо

  • Сильно ускоряет старт проекта.
  • Содержит готовые безопасные сценарии (JWT, reset password, verify email).
  • Гибкая архитектура: адаптеры БД, транспорты и менеджеры заменяемы.
  • Хорошая документация и примеры.

О чём стоит помнить

  • Проект в maintenance mode: стабильность да, новые возможности — нет.
  • Если вам нужна нетиповая модель пользователя (сложные ACL, мульти-тенантность, кастомные OAuth-флоу), придётся писать больше своего кода.
  • Абстракции добавляют слой сложности: новичкам иногда проще начать с «голого» FastAPI security, а потом мигрировать.

Когда выбирать fastapi-users, а когда нет

Берите fastapi-users, если:

  • вам нужен стандартный набор auth-фич «как везде»;
  • важна скорость разработки и предсказуемый результат;
  • проект живёт в проде и вы хотите минимизировать риски в безопасности.

Подумайте о ручной реализации (или альтернативе), если:

  • аутентификация — ядро продукта, и флоу сильно нестандартный;
  • нужно тесно интегрироваться с внешним IAM/SSO, где fastapi-users станет лишь тонкой прослойкой.

Альтернативы (коротко)

  • Собрать на встроенных security-механизмах FastAPI. Максимальный контроль, но больше работы и ответственности.
  • Внешние провайдеры (Auth0, Keycloak, Cognito). Отлично для enterprise-сценариев, но добавляют инфраструктуру и стоимость.

Полный цикл пользователя в fastapi-users с JWT

Ниже — связное описание стандартного пути пользователя в системе.

Регистрация: создание аккаунта

Пользователь заполняет форму регистрации (обычно email и пароль) и отправляет её. Клиент вызывает POST /register. fastapi-users создаёт пользователя в базе и возвращает профиль. Пароль в базе хранится только в виде хэша.

Запрос:

// POST /register
{
  "email": "user@example.com",
  "password": "secret123"
}

📢 Подписывайтесь на наш Telegram-канал.

Там вы найдете анонсы обучающих статей и видео, готовый код для ваших проектов и увлекательные курсы. Ничего лишнего — только практика, вдохновение и развитие.

👉 https://t.me/codelab_channel

Ответ:

{
  "id": "9f3e1d2c-8c2a-4b5a-b7ad-2d9c7d6c1b10",
  "email": "user@example.com",
  "is_active": true,
  "is_verified": false,
  "is_superuser": false
}

Если в проекте не используется подтверждение почты, пользователь может сразу переходить к входу. Если подтверждение включено — нужен следующий шаг.

Подтверждение email: включается по желанию

Когда верификация активна, пользователь после регистрации подтверждает адрес. Для повторной отправки письма клиент вызывает POST /request-verify-token. Сервер генерирует токен и через ваш хук отправляет письмо. Ответ всегда нейтральный (202), чтобы нельзя было определить, существует ли email.

Запрос:

// POST /request-verify-token
{
  "email": "user@example.com"
}

Пользователь кликает ссылку из письма, приложение отправляет токен в POST /verify. После этого is_verified становится true.

Запрос:

// POST /verify
{
  "token": "VERIFY_TOKEN_FROM_EMAIL"
}

Вход: получение JWT-токена

На экране входа пользователь вводит email и пароль. Клиент вызывает POST /login. Этот эндпоинт принимает форму (OAuth2 password flow), а не JSON. В ответ возвращается JWT.

Запрос (form):

username=user@example.com&password=secret123

Ответ (JSON):

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer"
}

Клиент сохраняет access_token и добавляет его в заголовок каждого защищённого запроса: Authorization: Bearer <access_token>.

Работа в приложении: токен как пропуск

Пока токен действителен, пользователь имеет доступ к защищённым эндпоинтам. Обычно сразу после входа или при запуске клиента вызывается GET /users/me — получить текущий профиль и проверить токен.

Ответ:

// GET /users/me
{
  "id": "9f3e1d2c-8c2a-4b5a-b7ad-2d9c7d6c1b10",
  "email": "user@example.com",
  "is_active": true,
  "is_verified": true,
  "is_superuser": false
}

Если токен просрочен или неверен, сервер вернёт 401, и клиент попросит войти снова.

Обновление профиля

Пользователь меняет данные профиля. Клиент отправляет частичный апдейт на PATCH /users/me. Передаются только изменённые поля.

Запрос:

// PATCH /users/me
{
  "full_name": "User Name"
}

Ответ: тот же профиль, но с обновлёнными полями.

Восстановление пароля

Если пароль забыт, сначала используется POST /forgot-password. Пользователь вводит email, сервер создаёт reset-токен и отправляет его письмом через ваш хук, но наружу отдаёт только 202.

Запрос:

// POST /forgot-password
{
  "email": "user@example.com"
}

Затем пользователь открывает письмо, вводит новый пароль, а клиент вызывает POST /reset-password с токеном и паролем.

Запрос:

// POST /reset-password
{
  "token": "RESET_TOKEN_FROM_EMAIL",
  "password": "newSecret123"
}

После успеха можно снова входить обычным логином.

Выход из системы

Пользователь нажимает «Выйти», клиент вызывает POST /logout. При JWT это в основном формальность: сервер не хранит сессии и не отзывает токен. Реальный выход происходит на клиенте — токен удаляется локально. После этого любой запрос без токена будет получать 401.