/
ivanstrike
/
tasker
Обзор
Документация
Войти
/
ivanstrike
/
tasker
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Program.cs
235 строк
11 KB
ivanstrike
Лабораторная работа 2
08 ноя 2025, 11:16
08 ноя 2025, 11:16
ec39293
Код
Авторство
О чём код?
using System.Text; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using TaskerApi.Data; using TaskerApi.Middleware; using TaskerApi.Services; using TaskerApi.Swagger; var builder = WebApplication.CreateBuilder(args); // Добавление контроллеров builder.Services.AddControllers(); // Настройка Entity Framework builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); // Настройка версионирования API builder.Services.AddApiVersioning(options => { options.DefaultApiVersion = new ApiVersion(1, 0); options.AssumeDefaultVersionWhenUnspecified = true; options.ReportApiVersions = true; }); builder.Services.AddVersionedApiExplorer(options => { options.GroupNameFormat = "'v'VVV"; options.SubstituteApiVersionInUrl = true; }); // Настройка JWT аутентификации var jwtSettings = builder.Configuration.GetSection("JwtSettings"); var secretKey = jwtSettings["SecretKey"]!; builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)), ValidateIssuer = true, ValidIssuer = jwtSettings["Issuer"], ValidateAudience = true, ValidAudience = jwtSettings["Audience"], ValidateLifetime = true, ClockSkew = TimeSpan.Zero }; }); builder.Services.AddAuthorization(); // Регистрация сервисов builder.Services.AddScoped<IJwtService, JwtService>(); // Настройка Swagger для всех версий API builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "Tasker API", Version = "v1", Description = "REST API для управления задачами и проектами (версия 1.0)\n\n" + "## Основные возможности:\n" + "- CRUD операции для задач и проектов\n" + "- JWT аутентификация\n" + "- Фильтрация задач по статусу, приоритету и проекту\n" + "- **Пагинация**: параметры `page` и `pageSize`\n\n" + "## Аутентификация:\n" + "1. Зарегистрируйтесь через /api/Auth/register\n" + "2. Войдите через /api/Auth/login для получения JWT токена\n" + "3. Используйте токен в заголовке: Authorization: Bearer {token}\n\n" + "## Пагинация:\n" + "Все endpoint'ы со списками поддерживают параметры:\n" + "- `page`: номер страницы (по умолчанию 1)\n" + "- `pageSize`: размер страницы (по умолчанию 20, максимум 100)\n\n" + "Ответы включают заголовки:\n" + "- X-Pagination-Page\n" + "- X-Pagination-TotalCount\n" + "- X-Pagination-TotalPages", Contact = new OpenApiContact { Name = "Tasker API Support", Email = "support@tasker.com" } }); options.SwaggerDoc("v2", new OpenApiInfo { Title = "Tasker API", Version = "v2", Description = "REST API для управления задачами и проектами (версия 2.0)\n\n" + "## Новые возможности в V2:\n" + "- Поддержка тегов для задач\n" + "- Оценка времени выполнения задач (EstimatedHours)\n" + "- Статистика по задачам (новый эндпоинт /api/v2/Tasks/statistics)\n" + "- Фильтрация задач по тегам\n" + "- **Выборочное включение полей**: параметр `include`\n\n" + "## Аддитивные изменения:\n" + "Версия 2.0 добавляет новые поля без нарушения обратной совместимости:\n" + "- EstimatedHours (int?) - необязательное поле\n" + "- Tags (List<string>?) - необязательный список тегов\n\n" + "## Опциональные поля (параметр include):\n" + "Вы можете указать, какие поля включить в ответ:\n" + "```\n" + "GET /api/v2/tasks?include=id,title,status,tags\n" + "```\n" + "Это уменьшает размер ответа и экономит трафик.\n\n" + "## Аутентификация:\n" + "1. Зарегистрируйтесь через /api/Auth/register\n" + "2. Войдите через /api/Auth/login для получения JWT токена\n" + "3. Используйте токен в заголовке: Authorization: Bearer {token}", Contact = new OpenApiContact { Name = "Tasker API Support", Email = "support@tasker.com" } }); options.SwaggerDoc("internal", new OpenApiInfo { Title = "Tasker Internal API", Version = "internal", Description = "Internal API для взаимодействия между микросервисами\n\n" + "## ТОЛЬКО ДЛЯ ВНУТРЕННИХ СЕРВИСОВ\n" + "Этот API предназначен исключительно для внутренних микросервисов.\n\n" + "## Аутентификация:\n" + "Используется API ключ в заголовке `X-Api-Key`\n\n" + "## Упрощения:\n" + "- Нет проверки владельца ресурсов\n" + "- Нет пагинации (для небольших выборок)\n" + "- Нет rate limiting\n" + "- Массовые операции для эффективности\n" + "- Упрощенные DTO (только необходимые поля)\n\n" + "## Основные endpoint'ы:\n" + "- Глобальная статистика\n" + "- Массовые операции с задачами\n" + "- Очистка служебных данных\n" + "- Health checks", Contact = new OpenApiContact { Name = "Internal Services Team", Email = "internal@tasker.com" } }); // Настройка аутентификации в Swagger для публичного API options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Name = "Authorization", Type = SecuritySchemeType.ApiKey, Scheme = "Bearer", BearerFormat = "JWT", In = ParameterLocation.Header, Description = "Введите JWT токен в формате: Bearer {ваш_токен}" }); // Настройка аутентификации для Internal API options.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme { Name = "X-Api-Key", Type = SecuritySchemeType.ApiKey, In = ParameterLocation.Header, Description = "Введите API ключ для доступа к внутреннему API" }); // Применение правильной схемы аутентификации в зависимости от группы API options.OperationFilter<SecurityRequirementsOperationFilter>(); // Подключаем XML комментарии если есть var xmlFile = $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); if (File.Exists(xmlPath)) { options.IncludeXmlComments(xmlPath); } }); // Настройка CORS builder.Services.AddCors(options => { options.AddPolicy("AllowAll", policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); }); var app = builder.Build(); // Инициализация базы данных using (var scope = app.Services.CreateScope()) { var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>(); context.Database.EnsureCreated(); } // Настройка pipeline if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "Tasker API V1"); options.SwaggerEndpoint("/swagger/v2/swagger.json", "Tasker API V2"); options.SwaggerEndpoint("/swagger/internal/swagger.json", "Internal API"); options.RoutePrefix = string.Empty; // Swagger UI на корневом пути options.DocumentTitle = "Tasker API Documentation"; options.DefaultModelsExpandDepth(-1); // Скрыть модели по умолчанию }); } app.UseCors("AllowAll"); // Применение middleware app.UseMiddleware<ApiKeyAuthMiddleware>(); // Проверка API ключа для internal endpoints app.UseMiddleware<RateLimitingMiddleware>(); // Rate limiting (не применяется к internal) app.UseMiddleware<IdempotencyMiddleware>(); // Идемпотентность app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();