diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs index d0686ef51..f7e807d8d 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Models/UpdateBasketItemsRequest.cs @@ -2,7 +2,6 @@ public class UpdateBasketItemsRequest { - public string BasketId { get; set; } public ICollection Updates { get; set; } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs index d6f7ae482..4f31b1da9 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Program.cs @@ -1,16 +1,146 @@ -await BuildWebHost(args).RunAsync(); -IWebHost BuildWebHost(string[] args) => - WebHost - .CreateDefaultBuilder(args) - .ConfigureAppConfiguration(cb => +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy()) + .AddUrlGroup(new Uri(builder.Configuration["CatalogUrlHC"]), name: "catalogapi-check", tags: new string[] { "catalogapi" }) + .AddUrlGroup(new Uri(builder.Configuration["OrderingUrlHC"]), name: "orderingapi-check", tags: new string[] { "orderingapi" }) + .AddUrlGroup(new Uri(builder.Configuration["BasketUrlHC"]), name: "basketapi-check", tags: new string[] { "basketapi" }) + .AddUrlGroup(new Uri(builder.Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }) + .AddUrlGroup(new Uri(builder.Configuration["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" }); + +builder.Services.Configure(builder.Configuration.GetSection("urls")); + +builder.Services.AddControllers() + .AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true); + +builder.Services.AddSwaggerGen(options => +{ + //options.DescribeAllEnumsAsStrings(); + options.SwaggerDoc("v1", new OpenApiInfo + { + Title = "Shopping Aggregator for Mobile Clients", + Version = "v1", + Description = "Shopping Aggregator for Mobile Clients" + }); + var identityUrl = builder.Configuration.GetSection("Identity").GetValue("ExternalUrl"); + options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme + { + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows() { - var sources = cb.Sources; - sources.Insert(3, new Microsoft.Extensions.Configuration.Json.JsonConfigurationSource() + Implicit = new OpenApiOAuthFlow() { - Optional = true, - Path = "appsettings.localhost.json", - ReloadOnChange = false - }); - }) - .UseStartup() - .Build(); + AuthorizationUrl = new Uri($"{identityUrl}/connect/authorize"), + TokenUrl = new Uri($"{identityUrl}/connect/token"), + + Scopes = new Dictionary() + { + { "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" } + } + } + } + }); + + options.OperationFilter(); +}); + +builder.Services.AddCors(options => +{ + options.AddPolicy("CorsPolicy", + builder => builder + .AllowAnyMethod() + .AllowAnyHeader() + .SetIsOriginAllowed((host) => true) + .AllowCredentials()); +}); + +JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); + +var identityUrl = builder.Configuration.GetValue("urls:identity"); + +builder.Services.AddAuthentication(options => +{ + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + +}) +.AddJwtBearer(options => +{ + options.Authority = identityUrl; + options.RequireHttpsMetadata = false; + options.Audience = "mobileshoppingagg"; + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateAudience = false + }; +}); + +builder.Services.AddAuthorization(options => +{ + options.AddPolicy("ApiScope", policy => + { + policy.RequireAuthenticatedUser(); + policy.RequireClaim("scope", "mobileshoppingagg"); + }); +}); + +builder.Services.AddTransient(); +builder.Services.AddSingleton(); +builder.Services.AddHttpClient(); + +builder.Services.AddTransient(); +builder.Services.AddScoped(); +builder.Services.AddGrpcClient((services, options) => +{ + var basketApi = services.GetRequiredService>().Value.GrpcBasket; + options.Address = new Uri(basketApi); +}).AddInterceptor(); +builder.Services.AddScoped(); +builder.Services.AddGrpcClient((services, options) => +{ + var catalogApi = services.GetRequiredService>().Value.GrpcCatalog; + options.Address = new Uri(catalogApi); +}).AddInterceptor(); +builder.Services.AddScoped(); +builder.Services.AddGrpcClient((services, options) => +{ + var orderingApi = services.GetRequiredService>().Value.GrpcOrdering; + options.Address = new Uri(orderingApi); +}).AddInterceptor(); + +var app = builder.Build(); + +var pathBase = app.Configuration["PATH_BASE"]; + +if (!string.IsNullOrEmpty(pathBase)) +{ + app.UsePathBase(pathBase); +} + +app.UseSwagger().UseSwaggerUI(c => +{ + c.SwaggerEndpoint($"{(!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty)}/swagger/v1/swagger.json", "Purchase BFF V1"); + + c.OAuthClientId("mobileshoppingaggswaggerui"); + c.OAuthClientSecret(string.Empty); + c.OAuthRealm(string.Empty); + c.OAuthAppName("Purchase BFF Swagger UI"); +}); + +app.UseRouting(); +app.UseCors("CorsPolicy"); +app.UseAuthentication(); +app.UseAuthorization(); +app.MapDefaultControllerRoute(); +app.MapControllers(); +app.MapHealthChecks("/hc", new HealthCheckOptions() +{ + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse +}); +app.MapHealthChecks("/liveness", new HealthCheckOptions +{ + Predicate = r => r.Name.Contains("self") +}); + +await app.RunAsync(); diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs index e1c9a24bf..bf9c1b7e9 100644 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs +++ b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Services/IBasketService.cs @@ -5,5 +5,4 @@ public interface IBasketService Task GetByIdAsync(string id); Task UpdateAsync(BasketData currentBasket); - } diff --git a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs b/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs deleted file mode 100644 index 8ece91d56..000000000 --- a/src/ApiGateways/Mobile.Bff.Shopping/aggregator/Startup.cs +++ /dev/null @@ -1,211 +0,0 @@ -namespace Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator; - -public class Startup -{ - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddHealthChecks() - .AddCheck("self", () => HealthCheckResult.Healthy()) - .AddUrlGroup(new Uri(Configuration["CatalogUrlHC"]), name: "catalogapi-check", tags: new string[] { "catalogapi" }) - .AddUrlGroup(new Uri(Configuration["OrderingUrlHC"]), name: "orderingapi-check", tags: new string[] { "orderingapi" }) - .AddUrlGroup(new Uri(Configuration["BasketUrlHC"]), name: "basketapi-check", tags: new string[] { "basketapi" }) - .AddUrlGroup(new Uri(Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }) - .AddUrlGroup(new Uri(Configuration["PaymentUrlHC"]), name: "paymentapi-check", tags: new string[] { "paymentapi" }); - - services.AddCustomMvc(Configuration) - .AddCustomAuthentication(Configuration) - .AddHttpServices() - .AddGrpcServices(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) - { - var pathBase = Configuration["PATH_BASE"]; - - if (!string.IsNullOrEmpty(pathBase)) - { - loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase); - app.UsePathBase(pathBase); - } - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseSwagger().UseSwaggerUI(c => - { - c.SwaggerEndpoint($"{(!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty)}/swagger/v1/swagger.json", "Purchase BFF V1"); - - c.OAuthClientId("mobileshoppingaggswaggerui"); - c.OAuthClientSecret(string.Empty); - c.OAuthRealm(string.Empty); - c.OAuthAppName("Purchase BFF Swagger UI"); - }); - - app.UseRouting(); - app.UseCors("CorsPolicy"); - app.UseAuthentication(); - app.UseAuthorization(); - app.UseEndpoints(endpoints => - { - endpoints.MapDefaultControllerRoute(); - endpoints.MapControllers(); - endpoints.MapHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - endpoints.MapHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - }); - } -} - -public static class ServiceCollectionExtensions -{ - public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) - { - services.AddOptions(); - services.Configure(configuration.GetSection("urls")); - - services.AddControllers() - .AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true); - - services.AddSwaggerGen(options => - { - //options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new OpenApiInfo - { - Title = "Shopping Aggregator for Mobile Clients", - Version = "v1", - Description = "Shopping Aggregator for Mobile Clients" - }); - var identityUrl = configuration.GetSection("Identity").GetValue("ExternalUrl"); - options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme - { - Type = SecuritySchemeType.OAuth2, - Flows = new OpenApiOAuthFlows() - { - Implicit = new OpenApiOAuthFlow() - { - AuthorizationUrl = new Uri($"{identityUrl}/connect/authorize"), - TokenUrl = new Uri($"{identityUrl}/connect/token"), - - Scopes = new Dictionary() - { - { "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" } - } - } - } - }); - - options.OperationFilter(); - }); - - services.AddCors(options => - { - options.AddPolicy("CorsPolicy", - builder => builder - .AllowAnyMethod() - .AllowAnyHeader() - .SetIsOriginAllowed((host) => true) - .AllowCredentials()); - }); - - return services; - } - public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) - { - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); - - var identityUrl = configuration.GetValue("urls:identity"); - - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - - }) - .AddJwtBearer(options => - { - options.Authority = identityUrl; - options.RequireHttpsMetadata = false; - options.Audience = "mobileshoppingagg"; - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateAudience = false - }; - }); - - return services; - } - public static IServiceCollection AddCustomAuthorization(this IServiceCollection services, IConfiguration configuration) - { - services.AddAuthorization(options => - { - options.AddPolicy("ApiScope", policy => - { - policy.RequireAuthenticatedUser(); - policy.RequireClaim("scope", "mobileshoppingagg"); - }); - }); - return services; - } - - public static IServiceCollection AddHttpServices(this IServiceCollection services) - { - //register delegating handlers - services.AddTransient(); - services.AddSingleton(); - - //register http services - - services.AddHttpClient(); - - return services; - } - - public static IServiceCollection AddGrpcServices(this IServiceCollection services) - { - services.AddTransient(); - - services.AddScoped(); - - services.AddGrpcClient((services, options) => - { - var basketApi = services.GetRequiredService>().Value.GrpcBasket; - options.Address = new Uri(basketApi); - }).AddInterceptor(); - - services.AddScoped(); - - services.AddGrpcClient((services, options) => - { - var catalogApi = services.GetRequiredService>().Value.GrpcCatalog; - options.Address = new Uri(catalogApi); - }).AddInterceptor(); - - services.AddScoped(); - - services.AddGrpcClient((services, options) => - { - var orderingApi = services.GetRequiredService>().Value.GrpcOrdering; - options.Address = new Uri(orderingApi); - }).AddInterceptor(); - - return services; - } - -}