using System.Text.Json.Nodes; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Persistence.Models.Configurations; using Swashbuckle.AspNetCore.SwaggerGen; namespace Persistence.API; public static class DependencyInjection { public static void AddSwagger(this IServiceCollection services, IConfiguration configuration) { services.AddSwaggerGen(c => { c.MapType(() => new OpenApiSchema { Type = "string", Example = new OpenApiString("0.00:00:00") }); c.MapType(() => new OpenApiSchema { Type = "string", Format = "date" }); c.MapType(() => new OpenApiSchema { AnyOf = new OpenApiSchema[] { new OpenApiSchema {Type = "string", Format = "string" }, new OpenApiSchema {Type = "number", Format = "int32" }, new OpenApiSchema {Type = "number", Format = "float" }, } }); c.CustomOperationIds(e => { return $"{e.ActionDescriptor.RouteValues["action"]}"; }); c.SwaggerDoc("v1", new OpenApiInfo { Title = "Persistence web api", Version = "v1" }); var needUseKeyCloak = configuration.GetSection("NeedUseKeyCloak").Get(); if (needUseKeyCloak) c.AddKeycloackSecurity(configuration); else c.AddDefaultSecurity(configuration); //var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; //var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); //var includeControllerXmlComment = true; //options.IncludeXmlComments(xmlPath, includeControllerXmlComment); //options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "AsbCloudApp.xml"), includeControllerXmlComment); }); } #region Authentication public static void AddJWTAuthentication(this IServiceCollection services, IConfiguration configuration) { var needUseKeyCloak = configuration .GetSection("NeedUseKeyCloak") .Get(); if (needUseKeyCloak) services.AddKeyCloakAuthentication(configuration); else services.AddDefaultAuthentication(configuration); } private static void AddKeyCloakAuthentication(this IServiceCollection services, IConfiguration configuration) { services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.RequireHttpsMetadata = false; options.Audience = configuration["Authentication:Audience"]; options.MetadataAddress = configuration["Authentication:MetadataAddress"]!; options.TokenValidationParameters = new TokenValidationParameters { ValidIssuer = configuration["Authentication:ValidIssuer"], }; }); } private static void AddDefaultAuthentication(this IServiceCollection services, IConfiguration configuration) { services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.RequireHttpsMetadata = false; options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = JwtParams.Issuer, ValidateAudience = true, ValidAudience = JwtParams.Audience, ValidateLifetime = true, IssuerSigningKey = JwtParams.SecurityKey, ValidateIssuerSigningKey = false }; options.Events = new JwtBearerEvents { OnMessageReceived = context => { var accessToken = context.Request.Headers["Authorization"] .ToString() .Replace(JwtBearerDefaults.AuthenticationScheme, string.Empty) .Trim(); context.Token = accessToken; return Task.CompletedTask; }, OnTokenValidated = context => { var username = context.Principal?.Claims .FirstOrDefault(e => e.Type == "username")?.Value; var password = context.Principal?.Claims .FirstOrDefault(e => e.Type == "password")?.Value; var keyCloakUser = configuration .GetSection(nameof(AuthUser)) .Get()!; if (username != keyCloakUser.Username || password != keyCloakUser.Password) { context.Fail("username or password did not match"); } return Task.CompletedTask; } }; }); } #endregion #region Security (Swagger) private static void AddKeycloackSecurity(this SwaggerGenOptions options, IConfiguration configuration) { options.AddSecurityDefinition("Keycloack", new OpenApiSecurityScheme { Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.OAuth2, Flows = new OpenApiOAuthFlows { Implicit = new OpenApiOAuthFlow { AuthorizationUrl = new Uri(configuration["Authentication:AuthorizationUrl"]), } } }); options.AddSecurityRequirement(new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Keycloack" }, Scheme = "Bearer", Name = "Bearer", In = ParameterLocation.Header, }, new List() } }); } private static void AddDefaultSecurity(this SwaggerGenOptions options, IConfiguration configuration) { options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, Scheme = "Bearer", }); options.AddSecurityRequirement(new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }, Scheme = "oauth2", Name = "Bearer", In = ParameterLocation.Header, }, new List() } }); } #endregion }