Security Module¶
Аутентификация, авторизация, ACL и управление сессиями.
Аутентификация¶
Bearer-токен в заголовке Authorization:
Цепочка аутентификации¶
Доступ к защищённым endpoint-ам охраняется FastAPI-зависимостью (Depends(AuthTokenApp.verify_access)) — не middleware. Это даёт точечный контроль: на одни роуты depend ставится, на другие — нет, и при этом каждый защищённый endpoint автоматически получает разобранную сессию в request.state.
sequenceDiagram
participant C as Client
participant D as Depends(verify_access)
participant DB as PostgreSQL
participant CV as ContextVar
C->>D: Request + Bearer token
D->>DB: SELECT session + user WHERE token = ?
DB-->>D: session_data
D->>D: Check expired_datetime > now()
D->>CV: set_access_session(session)
D->>D: request.state.session = session
D-->>C: Continue to router
Подключение к роутеру:
from fastapi import APIRouter, Depends
from backend.base.crm.security.app_security import AuthTokenApp
router = APIRouter(
dependencies=[Depends(AuthTokenApp.verify_access)],
)
После этого все handler'ы внутри router автоматически защищены — токен проверяется, сессия записывается в request.state.session.
Session¶
# Создание сессии (при логине)
session = Session(
user_id=user_id,
token=secrets.token_urlsafe(64),
ttl=3600,
expired_datetime=datetime.now(tz=utc) + timedelta(hours=1),
active=True,
)
await Session.create(session)
Получение сессии в роутере¶
@router.get("/me")
async def get_current_user(req: Request):
auth_session: "Session" = req.state.session # установлен Depends(verify_access)
user_id = auth_session.user_id.id # session.user_id — объект User
is_admin = auth_session.user_id.is_admin
return {"user_id": user_id, "is_admin": is_admin}
Access Control (ACL)¶
DotORM поддерживает встроенную проверку прав на уровне ORM через ContextVar:
from backend.base.system.dotorm.dotorm.access import (
set_access_session,
get_access_session,
)
# Устанавливается зависимостью verify_access автоматически
set_access_session(session)
# ORM проверяет при каждой операции:
await record.update(...) # → _check_access(Operation.UPDATE)
await Model.create(...) # → _check_access(Operation.CREATE)
await Model.search(...) # → _check_access(Operation.READ) + domain filter
Уровни доступа¶
- Table ACL — может ли пользователь вообще читать/писать таблицу
- Row Rules — видит ли пользователь конкретные записи (domain filter)
class Product(DotModel):
__table__ = "products"
__access__ = {
"read": True, # все могут читать
"create": "admin", # только админы создают
"update": "admin",
"delete": "admin",
}
SystemSession¶
Для операций от имени системы (cron, post_init) используется SystemSession:
from backend.base.crm.security.models.sessions import SystemSession
from backend.base.system.dotorm.dotorm.access import set_access_session
# Даёт полный доступ ко всем операциям
set_access_session(SystemSession(user_id=SYSTEM_USER_ID))
Только для серверного кода
SystemSession обходит все проверки доступа. Никогда не устанавливай его для пользовательских запросов.