@ -1,11 +0,0 @@ | |||
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Controllers; | |||
[Route("")] | |||
public class HomeController : Controller | |||
{ | |||
[HttpGet] | |||
public IActionResult Index() | |||
{ | |||
return new RedirectResult("~/swagger"); | |||
} | |||
} |
@ -0,0 +1,57 @@ | |||
public static class ServiceCollectionExtensions | |||
{ | |||
public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration) | |||
{ | |||
services.AddHealthChecks() | |||
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("CatalogUrlHC")), name: "catalogapi-check", tags: new string[] { "catalogapi" }) | |||
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("OrderingUrlHC")), name: "orderingapi-check", tags: new string[] { "orderingapi" }) | |||
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("BasketUrlHC")), name: "basketapi-check", tags: new string[] { "basketapi" }) | |||
.AddUrlGroup(_ => new Uri(configuration.GetRequiredValue("IdentityUrlHC")), name: "identityapi-check", tags: new string[] { "identityapi" }); | |||
return services; | |||
} | |||
public static IServiceCollection AddApplicationServices(this IServiceCollection services) | |||
{ | |||
// Register delegating handlers | |||
services.AddTransient<HttpClientAuthorizationDelegatingHandler>(); | |||
// Register http services | |||
services.AddHttpClient<IOrderApiClient, OrderApiClient>() | |||
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>(); | |||
return services; | |||
} | |||
public static IServiceCollection AddGrpcServices(this IServiceCollection services) | |||
{ | |||
services.AddTransient<GrpcExceptionInterceptor>(); | |||
services.AddScoped<IBasketService, BasketService>(); | |||
services.AddGrpcClient<Basket.BasketClient>((services, options) => | |||
{ | |||
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket; | |||
options.Address = new Uri(basketApi); | |||
}).AddInterceptor<GrpcExceptionInterceptor>(); | |||
services.AddScoped<ICatalogService, CatalogService>(); | |||
services.AddGrpcClient<Catalog.CatalogClient>((services, options) => | |||
{ | |||
var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog; | |||
options.Address = new Uri(catalogApi); | |||
}).AddInterceptor<GrpcExceptionInterceptor>(); | |||
services.AddScoped<IOrderingService, OrderingService>(); | |||
services.AddGrpcClient<GrpcOrdering.OrderingGrpc.OrderingGrpcClient>((services, options) => | |||
{ | |||
var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering; | |||
options.Address = new Uri(orderingApi); | |||
}).AddInterceptor<GrpcExceptionInterceptor>(); | |||
return services; | |||
} | |||
} |
@ -1,34 +0,0 @@ | |||
namespace Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters | |||
{ | |||
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<AuthorizeAttribute>().Any() || | |||
context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().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<OpenApiSecurityRequirement> | |||
{ | |||
new() | |||
{ | |||
[ oAuthScheme ] = new[] { "Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator" } | |||
} | |||
}; | |||
} | |||
} | |||
} | |||
} |
@ -1,38 +1,27 @@ | |||
global using CatalogApi; | |||
global using Grpc.Core.Interceptors; | |||
global using System; | |||
global using System.Collections.Generic; | |||
global using System.Linq; | |||
global using System.Net; | |||
global using System.Net.Http; | |||
global using System.Net.Http.Headers; | |||
global using System.Text.Json; | |||
global using System.Threading; | |||
global using System.Threading.Tasks; | |||
global using CatalogApi; | |||
global using Grpc.Core; | |||
global using Grpc.Core.Interceptors; | |||
global using GrpcBasket; | |||
global using HealthChecks.UI.Client; | |||
global using Microsoft.AspNetCore.Authentication; | |||
global using Microsoft.AspNetCore.Authorization; | |||
global using Microsoft.AspNetCore.Builder; | |||
global using Microsoft.AspNetCore.Diagnostics.HealthChecks; | |||
global using Microsoft.AspNetCore.Hosting; | |||
global using Microsoft.AspNetCore.Http; | |||
global using Microsoft.AspNetCore.Mvc; | |||
global using Microsoft.AspNetCore; | |||
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Config; | |||
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters; | |||
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Infrastructure; | |||
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Models; | |||
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator.Services; | |||
global using Microsoft.eShopOnContainers.Web.Shopping.HttpAggregator; | |||
global using Microsoft.Extensions.Configuration; | |||
global using Microsoft.Extensions.DependencyInjection; | |||
global using Microsoft.Extensions.Diagnostics.HealthChecks; | |||
global using Microsoft.Extensions.Hosting; | |||
global using Microsoft.Extensions.Logging; | |||
global using Microsoft.Extensions.Options; | |||
global using Microsoft.OpenApi.Models; | |||
global using Swashbuckle.AspNetCore.SwaggerGen; | |||
global using System.Collections.Generic; | |||
global using System.IdentityModel.Tokens.Jwt; | |||
global using System.Linq; | |||
global using System.Net.Http.Headers; | |||
global using System.Net.Http; | |||
global using System.Net; | |||
global using System.Text.Json; | |||
global using System.Threading.Tasks; | |||
global using System.Threading; | |||
global using System; | |||
global using Microsoft.IdentityModel.Tokens; | |||
global using Services.Common; |
@ -1,169 +1,42 @@ | |||
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.AddCustomMvc(builder.Configuration) | |||
.AddCustomAuthentication(builder.Configuration) | |||
.AddApplicationServices() | |||
.AddGrpcServices(); | |||
var app = builder.Build(); | |||
if (!app.Environment.IsDevelopment()) | |||
{ | |||
app.UseExceptionHandler("/Home/Error"); | |||
} | |||
var pathBase = builder.Configuration["PATH_BASE"]; | |||
if (!string.IsNullOrEmpty(pathBase)) | |||
{ | |||
app.UsePathBase(pathBase); | |||
} | |||
builder.AddServiceDefaults(); | |||
app.UseHttpsRedirection(); | |||
builder.Services.AddControllers(); | |||
app.UseSwagger().UseSwaggerUI(c => | |||
builder.Services.AddHealthChecks(builder.Configuration); | |||
builder.Services.AddCors(options => | |||
{ | |||
c.SwaggerEndpoint($"{(!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty)}/swagger/v1/swagger.json", "Purchase BFF V1"); | |||
c.OAuthClientId("webshoppingaggswaggerui"); | |||
c.OAuthClientSecret(string.Empty); | |||
c.OAuthRealm(string.Empty); | |||
c.OAuthAppName("web shopping bff Swagger UI"); | |||
options.AddPolicy("CorsPolicy", | |||
builder => builder | |||
.SetIsOriginAllowed((host) => true) | |||
.AllowAnyMethod() | |||
.AllowAnyHeader() | |||
.AllowCredentials()); | |||
}); | |||
app.UseRouting(); | |||
app.UseCors("CorsPolicy"); | |||
app.UseAuthentication(); | |||
app.UseAuthorization(); | |||
builder.Services.AddApplicationServices(); | |||
builder.Services.AddGrpcServices(); | |||
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") | |||
}); | |||
builder.Services.Configure<UrlsConfig>(builder.Configuration.GetSection("urls")); | |||
await app.RunAsync(); | |||
var app = builder.Build(); | |||
public static class ServiceCollectionExtensions | |||
if (!await app.CheckHealthAsync()) | |||
{ | |||
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) | |||
{ | |||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); | |||
var identityUrl = configuration.GetValue<string>("urls:identity"); | |||
services.AddAuthentication("Bearer") | |||
.AddJwtBearer(options => | |||
{ | |||
options.Authority = identityUrl; | |||
options.RequireHttpsMetadata = false; | |||
options.Audience = "webshoppingagg"; | |||
options.TokenValidationParameters = new TokenValidationParameters | |||
{ | |||
ValidateAudience = false | |||
}; | |||
}); | |||
return services; | |||
} | |||
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) | |||
{ | |||
services.Configure<UrlsConfig>(configuration.GetSection("urls")); | |||
services.AddControllers() | |||
.AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true); | |||
services.AddSwaggerGen(options => | |||
{ | |||
options.SwaggerDoc("v1", new OpenApiInfo | |||
{ | |||
Title = "Shopping Aggregator for Web Clients", | |||
Version = "v1", | |||
Description = "Shopping Aggregator for Web Clients" | |||
}); | |||
var identityUrl = configuration.GetSection("Identity").GetValue<string>("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<string, string>() | |||
{ | |||
{ "webshoppingagg", "Shopping Aggregator for Web Clients" } | |||
} | |||
} | |||
} | |||
}); | |||
options.OperationFilter<AuthorizeCheckOperationFilter>(); | |||
}); | |||
services.AddCors(options => | |||
{ | |||
options.AddPolicy("CorsPolicy", | |||
builder => builder | |||
.SetIsOriginAllowed((host) => true) | |||
.AllowAnyMethod() | |||
.AllowAnyHeader() | |||
.AllowCredentials()); | |||
}); | |||
return services; | |||
} | |||
public static IServiceCollection AddApplicationServices(this IServiceCollection services) | |||
{ | |||
//register delegating handlers | |||
services.AddTransient<HttpClientAuthorizationDelegatingHandler>(); | |||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); | |||
//register http services | |||
services.AddHttpClient<IOrderApiClient, OrderApiClient>() | |||
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>(); | |||
return services; | |||
} | |||
public static IServiceCollection AddGrpcServices(this IServiceCollection services) | |||
{ | |||
services.AddTransient<GrpcExceptionInterceptor>(); | |||
services.AddScoped<IBasketService, BasketService>(); | |||
return; | |||
} | |||
services.AddGrpcClient<Basket.BasketClient>((services, options) => | |||
{ | |||
var basketApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcBasket; | |||
options.Address = new Uri(basketApi); | |||
}).AddInterceptor<GrpcExceptionInterceptor>(); | |||
app.UseServiceDefaults(); | |||
services.AddScoped<ICatalogService, CatalogService>(); | |||
app.UseHttpsRedirection(); | |||
services.AddGrpcClient<Catalog.CatalogClient>((services, options) => | |||
{ | |||
var catalogApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcCatalog; | |||
options.Address = new Uri(catalogApi); | |||
}).AddInterceptor<GrpcExceptionInterceptor>(); | |||
app.UseCors("CorsPolicy"); | |||
app.UseAuthentication(); | |||
app.UseAuthorization(); | |||
services.AddScoped<IOrderingService, OrderingService>(); | |||
app.MapGet("/", () => Results.Redirect("/swagger")); | |||
services.AddGrpcClient<GrpcOrdering.OrderingGrpc.OrderingGrpcClient>((services, options) => | |||
{ | |||
var orderingApi = services.GetRequiredService<IOptions<UrlsConfig>>().Value.GrpcOrdering; | |||
options.Address = new Uri(orderingApi); | |||
}).AddInterceptor<GrpcExceptionInterceptor>(); | |||
app.MapControllers(); | |||
return services; | |||
} | |||
} | |||
await app.RunAsync(); |
@ -1,29 +1,16 @@ | |||
{ | |||
"iisSettings": { | |||
"windowsAuthentication": false, | |||
"anonymousAuthentication": true, | |||
"iisExpress": { | |||
"applicationUrl": "http://localhost:57425/", | |||
"sslPort": 0 | |||
} | |||
}, | |||
"profiles": { | |||
"IIS Express": { | |||
"commandName": "IISExpress", | |||
"launchBrowser": true, | |||
"launchUrl": "api/values", | |||
"environmentVariables": { | |||
"ASPNETCORE_ENVIRONMENT": "Development" | |||
} | |||
}, | |||
"PurchaseForMvc": { | |||
"Web.Shopping.HttpAggregator": { | |||
"commandName": "Project", | |||
"launchBrowser": true, | |||
"launchUrl": "api/values", | |||
"applicationUrl": "http://localhost:61632/", | |||
"environmentVariables": { | |||
"CatalogUrlHC": "http://localhost:5222/hc", | |||
"OrderingUrlHC": "http://localhost:5224/hc", | |||
"BasketUrlHC": "http://localhost:5221/hc", | |||
"IdentityUrlHC": "http://localhost:5223/hc", | |||
"ASPNETCORE_ENVIRONMENT": "Development" | |||
}, | |||
"applicationUrl": "http://localhost:61632/" | |||
} | |||
} | |||
} | |||
} |
@ -1,16 +1,8 @@ | |||
{ | |||
"Logging": { | |||
"Debug": { | |||
"IncludeScopes": false, | |||
"LogLevel": { | |||
"Default": "Debug" | |||
} | |||
}, | |||
"Console": { | |||
"IncludeScopes": false, | |||
"LogLevel": { | |||
"Default": "Debug" | |||
} | |||
"LogLevel": { | |||
"Default": "Information", | |||
"Microsoft.AspNetCore": "Warning" | |||
} | |||
} | |||
} |
@ -1,20 +1,29 @@ | |||
{ | |||
"Identity": { | |||
"Url": "http://localhost:5105", | |||
"Audience": "webshoppingagg" | |||
}, | |||
"Logging": { | |||
"Debug": { | |||
"IncludeScopes": false, | |||
"LogLevel": { | |||
"Default": "Warning" | |||
} | |||
"LogLevel": { | |||
"Default": "Information", | |||
"Microsoft.AspNetCore": "Warning" | |||
} | |||
}, | |||
"OpenApi": { | |||
"Endpoint": { | |||
"Name": "Purchase BFF V1" | |||
}, | |||
"Console": { | |||
"IncludeScopes": false, | |||
"LogLevel": { | |||
"Default": "Warning" | |||
} | |||
"Document": { | |||
"Description": "Shopping Aggregator for Web Clients", | |||
"Title": "Shopping Aggregator for Web Clients", | |||
"Version": "v1" | |||
}, | |||
"Auth": { | |||
"ClientId": "webshoppingaggswaggerui", | |||
"AppName": "web shopping bff Swagger UI" | |||
} | |||
}, | |||
"Identity": { | |||
"Url": "http://localhost:5105", | |||
"Audience": "webshoppingagg", | |||
"Scopes": { | |||
"webshoppingagg": "Shopping Aggregator for Web Clients" | |||
} | |||
} | |||
} |