diff --git a/Webshop.Api/Program.cs b/Webshop.Api/Program.cs index 4419a6d..e5eaf67 100644 --- a/Webshop.Api/Program.cs +++ b/Webshop.Api/Program.cs @@ -10,7 +10,9 @@ using Webshop.Domain.Interfaces; using Webshop.Infrastructure.Data; using Webshop.Infrastructure.Repositories; using Microsoft.AspNetCore.HttpOverrides; -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; +using Webshop.Api.SwaggerFilters; var builder = WebApplication.CreateBuilder(args); @@ -70,7 +72,39 @@ builder.Services.AddScoped(); // 5. Controller und Swagger/OpenAPI hinzufügen builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); -builder.Services.AddSwaggerGen(); + +builder.Services.AddSwaggerGen(c => +{ + // 1. JWT Security Definition hinzufügen + c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", + Name = "Authorization", + In = ParameterLocation.Header, // Der Token wird im Header gesendet + Type = SecuritySchemeType.Http, // Dies ist ein HTTP-Schema + Scheme = "Bearer" // Das Schema ist "Bearer" + }); + + // 2. Security Requirement für alle Operationen hinzufügen + c.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" // Verweist auf die oben definierte "Bearer" Sicherheit + } + }, + new string[] {} // Keine spezifischen "Scopes" für JWT (leer lassen) + } + }); + + // 3. Optional: Filtern und Anzeigen von Autorisierungsinformationen (Rollen) + // Damit Swagger die "Authorize"-Informationen von Ihren Controllern anzeigt. + c.OperationFilter(); +}); // --- ENDE: DIENSTE ZUM CONTAINER HINZUFÜGEN --- diff --git a/Webshop.Api/SwaggerFilters/AuthorizeOperationFilter.cs b/Webshop.Api/SwaggerFilters/AuthorizeOperationFilter.cs new file mode 100644 index 0000000..b530e55 --- /dev/null +++ b/Webshop.Api/SwaggerFilters/AuthorizeOperationFilter.cs @@ -0,0 +1,65 @@ +// src/Webshop.Api/SwaggerFilters/AuthorizeOperationFilter.cs +using Microsoft.AspNetCore.Authorization; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Linq; // Für .Any(), .Union(), .Select() +using System.Collections.Generic; // Für List + +namespace Webshop.Api.SwaggerFilters +{ + public class AuthorizeOperationFilter : IOperationFilter + { + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + // Überprüfe, ob die Methode oder der Controller ein [Authorize]-Attribut hat + // und kein [AllowAnonymous]-Attribut. + var authorizeAttributes = context.MethodInfo.DeclaringType.GetCustomAttributes(true) + .Union(context.MethodInfo.GetCustomAttributes(true)) + .OfType(); + + var allowAnonymousAttributes = context.MethodInfo.DeclaringType.GetCustomAttributes(true) + .Union(context.MethodInfo.GetCustomAttributes(true)) + .OfType(); + + // Wenn Authorize-Attribute vorhanden sind UND kein AllowAnonymous-Attribut (für die Operation) + if (authorizeAttributes.Any() && !allowAnonymousAttributes.Any()) + { + // Füge ein "lock" Symbol in Swagger UI hinzu + operation.Security = new List + { + new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Type = ReferenceType.SecurityScheme, + Id = "Bearer" // Verweis auf die JWT-Definition in Program.cs + } + }, + new List() // Scopes, hier leer für JWT + } + } + }; + + // Füge Rolleninformationen zur Beschreibung des Endpunkts hinzu (optional, aber hilfreich) + var requiredRoles = authorizeAttributes + .Select(attr => attr.Roles) + .Where(roles => !string.IsNullOrWhiteSpace(roles)) + .SelectMany(roles => roles.Split(',')) + .Distinct() + .ToList(); + + if (requiredRoles.Any()) + { + operation.Summary += $" (Auth Required: {string.Join(", ", requiredRoles)})"; + } + else + { + operation.Summary += " (Auth Required)"; + } + } + } + } +} \ No newline at end of file