ADR-SRV-004. Конфигурация бэка и CORS
Бэк должен разворачиваться на стенде, где фронт и API — на разных origin. Фиксируем: параметры
среды берутся из appsettings (стандартный конфиг ASP.NET, подменяется деплоем), список разрешённых
origin фронта — из Cors:AllowedOrigins (allowlist по среде); в локальной разработке (список пуст) CORS
разрешает любой origin. Swagger UI — только вне прода.
1. Контекст и постановка задачи
Сервис разворачивается на стендах (dev/stage/prod). Фронт и API там — на разных origin, поэтому бэку нужен CORS-allowlist: браузер разрешит запрос со страницы фронта, только если его origin в списке разрешённых. Список различается по среде, а артефакт сборки — один, значит origin'ы нельзя «зашивать» в код.
Нужно зафиксировать: откуда бэк берёт параметры среды и как настраивается CORS, чтобы разворачивание было предсказуемым, а локальная разработка не требовала ручной настройки.
2. Драйверы решения
- Один билд на все среды — параметры подменяются конфигом, не пересборкой.
- Безопасность CORS — на стенде разрешаем только известные origin фронта, не «любой».
- Ноль трения локально —
ng serveна :4200 ходит на бэк без ручной настройки CORS. - Стандартные механизмы ASP.NET —
appsettings,IConfiguration, без своих слоёв.
3. Рассмотренные варианты
- A (выбран). Параметры среды — в
appsettings;Cors:AllowedOrigins— allowlist из конфига; пустой список = разрешить любой origin (локальная разработка). - B. Всегда
AllowAnyOrigin. Просто, но на стенде небезопасно. - C. Origin'ы в переменных окружения/коде. Дробит конфиг, хуже читается, чем один
appsettings.
4. Решение
Выбран Вариант A.
4.1. Параметры среды — в appsettings
appsettings.json — стандартный конфиг ASP.NET (IConfiguration). На стенде файл подменяется
деплоем (генерится devops/configs-generator вместе с рантайм-конфигом фронта). В репозитории —
значения для локальной разработки. Имя окружения задаётся ASPNETCORE_ENVIRONMENT при запуске.
4.2. CORS — allowlist из конфига
"Cors": { "AllowedOrigins": ["https://sok.dev.example"] }
var allowedOrigins = builder.Configuration.GetSection("Cors:AllowedOrigins").Get<string[]>() ?? [];
builder.Services.AddCors(o => o.AddPolicy(policy, p =>
{
if (allowedOrigins.Length > 0)
p.WithOrigins(allowedOrigins).AllowAnyHeader().AllowAnyMethod();
else
p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod(); // локальная разработка
}));
app.UseCors(policy);
- Список задан (стенд) → разрешаем только эти origin.
- Список пуст (локальная разработка) → разрешаем любой origin, чтобы
ng serveработал без настройки.
4.3. Swagger UI — только вне прода
Браузерная страница /swagger включается только при ASPNETCORE_ENVIRONMENT=Development
(на проде — выключена). Сам контракт /openapi/v1.json отдаётся всегда.
4.4. Что не делаем
- Не зашиваем origin'ы в код.
- Не оставляем
AllowAnyOriginна стенде. - Не заводим свой слой конфигурации поверх
IConfiguration.
5. Положительные следствия
- Один билд → все среды; CORS и параметры меняет только конфиг.
- На стенде CORS ограничен известными origin.
- Локальная разработка — без ручной настройки CORS.
6. Отрицательные следствия и компромиссы
- Пустой список = «любой origin» удобен локально, но опасен, если случайно уедет на стенд — поэтому на стендах список обязателен и проверяется при деплое.
7. Проверка
- С заданным
Cors:AllowedOriginsзапрос с чужого origin блокируется браузером, с разрешённого — проходит. - С пустым списком локальный
ng serve(:4200) ходит на бэк (:5080) без ошибок CORS. - На проде
/swaggerнедоступен;/openapi/v1.jsonдоступен.
8. Открытые вопросы / отложено
- Строки подключения к БД — появятся в
appsettingsс введением персистентности (ADR-SRV-003). - Секреты — не в коммитимом
appsettings: локально —appsettings.Local.json(в.gitignore, подключается вProgram.cs, грузится в любой среде), на стендах — через devops-генератор / переменные окружения (напр.Orthocover:ApiKey, ADR-SRV-005). Полноценная аутентификация — с auth-срезом. - Проверка непустого allowlist на не-Development — можно добавить fail-fast при старте.