← Назад к курсу

Фундаментальные концепции веб-разработки на Python, от выбора фреймворка до сложных паттернов и обеспечения безопасности.

🧭 Часть 1: Выбор фреймворка для вашего проекта

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

Следующая таблица поможет вам сделать осознанный выбор, сравнив ключевые аспекты этих фреймворков.

Критерий Django (Полноценный фреймворк) Flask (Микрофреймворк) Pyramid (Универсальный фреймворк)
Философия «Batteries included». Готовое решение. Гибкость и минимализм. Гибкость и масштабируемость.
Архитектура Строгое следование MTV (Model-Template-View). Не навязывает архитектуру, но предлагает паттерны. Не навязывает архитектуру.
Идеальный сценарий Сложные приложения (CMS, соцсети), где важна скорость разработки. Проекты с микросервисной архитектурой, API, небольшие приложения. Сложные, масштабируемые приложения, где требования могут меняться.

Выбор фреймворка определяет вашу архитектуру. Теперь рассмотрим ключевые архитектурные паттерны.

📐 Часть 2: Архитектурные паттерны — CQRS

Для сложных систем с высокой нагрузкой часто используется паттерн CQRS (Command Query Responsibility Segregation).

Этот подход разделяет операции записи данных (Commands) и чтения данных (Queries) на разные модели, что позволяет оптимизировать каждую из них под конкретную задачу. Например, модель для записи может быть нормализована для обеспечения консистентности, а модель для чтения — денормализована для максимальной скорости.

Ключевые компоненты CQRS

  • Команда (Command): Объект, представляющий намерение изменить состояние системы (например, CreateOrderCommand).
  • Обработчик команд (Command Handler): Принимает команду и выполняет бизнес-логику, обновляя модель записи (Write Model).
  • Событие (Event): Объект, описывающий факт, который уже произошел в системе (например, OrderCreatedEvent).
  • Модель чтения (Read Model): Оптимизированная модель данных, предназначенная только для запросов. Обновляется асинхронно через обработчики событий (Event Handlers).

В Python для реализации CQRS можно использовать библиотеку Diator, которая предоставляет готовые абстракции для команд, запросов, событий и их обработчиков.

Код ниже демонстрирует основные компоненты паттерна CQRS в Python с использованием библиотеки Diator:

import dataclasses
from datetime import datetime
from diator.requests import Request, RequestHandler
from diator.response import Response
from diator.events import DomainEvent, EventHandler

# --- Команда и её обработчик ---
@dataclasses.dataclass(frozen=True, kw_only=True)
class CreateOrderCommand(Request):
    user_id: int
    item: str

class CreateOrderCommandHandler(RequestHandler[CreateOrderCommand, None]):
    async def handle(self, request: CreateOrderCommand) -> None:
        # 1. Выполняем бизнес-логику и сохраняем заказ (Write Model)
        # 2. Генерируем событие
        order_created = OrderCreatedEvent(user_id=request.user_id, item=request.item)
        # ... (обычно событие отправляется через медиатор/шину событий)

# --- Событие ---
@dataclasses.dataclass(frozen=True, kw_only=True)
class OrderCreatedEvent(DomainEvent):
    user_id: int
    item: str
    timestamp: datetime = dataclasses.field(default_factory=datetime.utcnow)

# --- Запрос и его обработчик ---
@dataclasses.dataclass(frozen=True, kw_only=True)
class GetUserOrdersQuery(Request):
    user_id: int

@dataclasses.dataclass(frozen=True, kw_only=True)
class GetUserOrdersQueryResult(Response):
    orders: list[str]

class GetUserOrdersQueryHandler(RequestHandler[GetUserOrdersQuery, GetUserOrdersQueryResult]):
    async def handle(self, request: GetUserOrdersQuery) -> GetUserOrdersQueryResult:
        # Запрашиваем данные из оптимизированной модели чтения (Read Model)
        # Например, из специальной таблицы в БД или кэша
        user_orders = [...]  # Здесь логика выборки
        return GetUserOrdersQueryResult(orders=user_orders)

🔐 Часть 3: Безопасность: общие принципы и защита от атак

Безопасность — критически важный аспект, и подход к ней зависит от выбранного фреймворка.

Механизмы безопасности во фреймворках

  • Django: Предоставляет мощную встроенную защиту от большинства распространенных атак.
  • Flask и FastAPI: Дают гибкость в настройке безопасности. Для защиты от SQL-инъекций рекомендуется использовать ORM (например, SQLAlchemy), а для аутентификации — стандартные библиотеки, такие как PyJWT и passlib.

Ключевые практики безопасности

Эти рекомендации универсальны для любого проекта на Python:

  1. Актуальность: Всегда используйте последние поддерживаемые версии Python и библиотек.
  2. Защита секретов: Никогда не храните пароли, ключи API в коде. Используйте переменные окружения.
  3. Валидация ввода: Всегда проверяйте и санируйте (очищайте) пользовательский ввод.
  4. HTTPS: На production-серверах используйте HTTPS и настройте перенаправление с HTTP.
  5. Отладка: Отключайте режим отладки (DEBUG = False) на серверах.

В следующей таблице перечислены основные типы атак и способы защиты от них в контексте Python-разработки.

Угроза Описание Методы защиты
SQL-инъекция Внедрение вредоносного SQL-кода. Использование ORM (Django ORM, SQLAlchemy) или параметризованных запросов.
XSS (Межсайтовый скриптинг) Внедрение вредоносных скриптов на страницу. Автоматическое экранирование (Django шаблоны), санация вывода.
CSRF (Межсайтовая подделка запроса) Выполнение действий от имени пользователя без его ведома. Использование CSRF-токенов (встроено в Django).
Небезопасная аутентификация Кража или подбор учетных данных. Хеширование паролей с «солью» (bcrypt, Argon2), JWT с истечением срока действия.

🔑 Часть 4: Аутентификация и JWT

Для современных API стандартом де-факто стала аутентификация с помощью JWT (JSON Web Tokens).

JWT — это компактный токен, состоящий из трех частей: заголовка, полезной нагрузки (payload) и подписи. Он подписан, что позволяет проверить его целостность, но не зашифрован (если не используется дополнительное шифрование JWE).

Основные шаги для работы с JWT в FastAPI/Flask:

  1. Установите библиотеки: pip install pyjwt cryptography passlib.
  2. При входе пользователя проверьте его учетные данные и сгенерируйте токен с помощью jwt.encode(), указав полезные данные (например, sub — идентификатор пользователя) и секретный ключ.
  3. Пользователь отправляет токен в заголовке Authorization: Bearer <токен>.
  4. На защищенных маршрутах декодируйте и проверяйте токен с помощью jwt.decode().

Код ниже демонстрирует базовую логику создания и проверки JWT-токена:

import jwt
from datetime import datetime, timedelta, timezone

SECRET_KEY = "your_super_secret_key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

def verify_token(token: str):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except jwt.ExpiredSignatureError:
        # Токен истек
        return None
    except jwt.InvalidTokenError:
        # Неверный токен
        return None

# Пример создания токена для пользователя с id=123
token = create_access_token(data={"sub": "123"})
print(f"JWT Token: {token}")

# Пример проверки
payload = verify_token(token)
if payload:
    print(f"Данные в токене: {payload}")

💎 Заключение: от выбора к практике

Мы прошли ключевые этапы:

  1. Выбор фреймворка — основа архитектуры.
  2. Архитектурный паттерн CQRS — для масштабирования сложных систем.
  3. Безопасность — фундаментальные практики для любого проекта.
  4. Аутентификация через JWT — стандарт для современных API.

Чтобы закрепить знания, попробуйте создать простое веб-приложение с аутентификацией на выбранном фреймворке, следуя принципам безопасности.

Для более глубокого изучения обратитесь к официальной документации выбранного фреймворка и ресурсам OWASP.