diff --git a/src/Services/Basket/Basket.API/Infrastructure/Middlewares/AuthorizeCheckOperationFilter.cs b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/AuthorizeCheckOperationFilter.cs new file mode 100644 index 000000000..4a1c24aa6 --- /dev/null +++ b/src/Services/Basket/Basket.API/Infrastructure/Middlewares/AuthorizeCheckOperationFilter.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; +using System.Linq; + +namespace Basket.API.Infrastructure.Filters +{ + public class AuthorizeCheckOperationFilter : IOperationFilter + { + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + // Check for authorize attribute + var hasAuthorize = context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType().Any() || + context.MethodInfo.GetCustomAttributes(true).OfType().Any(); + + if (!hasAuthorize) return; + + operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" }); + operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" }); + + var oAuthScheme = new OpenApiSecurityScheme + { + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } + }; + + operation.Security = new List + { + new OpenApiSecurityRequirement + { + [ oAuthScheme ] = new [] { "basketapi" } + } + }; + } + } +} \ No newline at end of file diff --git a/src/Services/Basket/Basket.API/Startup.cs b/src/Services/Basket/Basket.API/Startup.cs index 3620b0b00..098428ad9 100644 --- a/src/Services/Basket/Basket.API/Startup.cs +++ b/src/Services/Basket/Basket.API/Startup.cs @@ -55,6 +55,37 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API }).AddNewtonsoftJson(); + services.AddSwaggerGen(options => + { + options.DescribeAllEnumsAsStrings(); + options.SwaggerDoc("v1", new OpenApiInfo + { + Title = "eShopOnContainers - Basket HTTP API", + Version = "v1", + Description = "The Basket Service HTTP API" + }); + + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme + { + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows() + { + Implicit = new OpenApiOAuthFlow() + { + AuthorizationUrl = new Uri($"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), + TokenUrl = new Uri($"{Configuration.GetValue("IdentityUrlExternal")}/connect/token"), + Scopes = new Dictionary() + { + { "basket", "Basket API" } + } + } + } + }); + + options.OperationFilter(); + }); + + ConfigureAuthService(services); services.AddCustomHealthCheck(Configuration); @@ -124,33 +155,6 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API RegisterEventBus(services); - services.AddSwaggerGen(options => - { - options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new OpenApiInfo - { - Title = "eShopOnContainers - Basket HTTP API", - Version = "v1", - Description = "The Basket Service HTTP API" - }); - - options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme - { - Type = SecuritySchemeType.OAuth2, - Flows = new OpenApiOAuthFlows() - { - Implicit = new OpenApiOAuthFlow() - { - AuthorizationUrl = new Uri($"{Configuration.GetValue("IdentityUrlExternal")}/connect/authorize"), - TokenUrl = new Uri($"{Configuration.GetValue("IdentityUrlExternal")}/connect/token"), - Scopes = new Dictionary() - { - { "basket", "Basket API" } - } - } - } - }); - }); services.AddCors(options => { @@ -185,20 +189,12 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API app.UsePathBase(pathBase); } + app.UseRouting(); ConfigureAuth(app); app.UseStaticFiles(); - app.UseSwagger() - .UseSwaggerUI(setup => - { - setup.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1"); - setup.OAuthClientId("basketswaggerui"); - setup.OAuthAppName("Basket Swagger UI"); - }); - app.UseCors("CorsPolicy"); - app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); @@ -213,6 +209,15 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API Predicate = r => r.Name.Contains("self") }); }); + + app.UseSwagger() + .UseSwaggerUI(setup => + { + setup.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Basket.API V1"); + setup.OAuthClientId("basketswaggerui"); + setup.OAuthAppName("Basket Swagger UI"); + }); + ConfigureEventBus(app); } @@ -226,7 +231,7 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API private void ConfigureAuthService(IServiceCollection services) { // prevent from mapping "sub" claim to nameidentifier. - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); var identityUrl = Configuration.GetValue("IdentityUrl"); @@ -250,8 +255,8 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API app.UseMiddleware(); } - app.UseAuthorization(); app.UseAuthentication(); + app.UseAuthorization(); } private void RegisterEventBus(IServiceCollection services)