|
|
@ -1,7 +1,6 @@ |
|
|
|
using Microsoft.AspNetCore.Authentication.JwtBearer; |
|
|
|
using Microsoft.AspNetCore.Builder; |
|
|
|
using Microsoft.AspNetCore.Hosting; |
|
|
|
using Microsoft.AspNetCore.Http; |
|
|
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Config; |
|
|
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Filters.Basket.API.Infrastructure.Filters; |
|
|
|
using Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregator.Infrastructure; |
|
|
@ -19,166 +18,166 @@ using System.Net.Http; |
|
|
|
|
|
|
|
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.AddCustomMvc(Configuration) |
|
|
|
.AddCustomAuthentication(Configuration) |
|
|
|
.AddHttpServices(); |
|
|
|
} |
|
|
|
|
|
|
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
|
|
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) |
|
|
|
{ |
|
|
|
var pathBase = Configuration["PATH_BASE"]; |
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(pathBase)) |
|
|
|
{ |
|
|
|
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); |
|
|
|
app.UsePathBase(pathBase); |
|
|
|
} |
|
|
|
|
|
|
|
app.UseCors("CorsPolicy"); |
|
|
|
|
|
|
|
if (env.IsDevelopment()) |
|
|
|
{ |
|
|
|
app.UseDeveloperExceptionPage(); |
|
|
|
} |
|
|
|
|
|
|
|
app.UseAuthentication(); |
|
|
|
|
|
|
|
app.UseMvc(); |
|
|
|
|
|
|
|
app.UseSwagger().UseSwaggerUI(c => |
|
|
|
{ |
|
|
|
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); |
|
|
|
c.ConfigureOAuth2("Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI"); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public static class ServiceCollectionExtensions |
|
|
|
{ |
|
|
|
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) |
|
|
|
{ |
|
|
|
services.AddOptions(); |
|
|
|
services.Configure<UrlsConfig>(configuration.GetSection("urls")); |
|
|
|
|
|
|
|
services.AddMvc().SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1); |
|
|
|
|
|
|
|
services.AddSwaggerGen(options => |
|
|
|
{ |
|
|
|
options.DescribeAllEnumsAsStrings(); |
|
|
|
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info |
|
|
|
{ |
|
|
|
Title = "Shopping Aggregator for Mobile Clients", |
|
|
|
Version = "v1", |
|
|
|
Description = "Shopping Aggregator for Mobile Clients", |
|
|
|
TermsOfService = "Terms Of Service" |
|
|
|
}); |
|
|
|
|
|
|
|
options.AddSecurityDefinition("oauth2", new OAuth2Scheme |
|
|
|
{ |
|
|
|
Type = "oauth2", |
|
|
|
Flow = "implicit", |
|
|
|
AuthorizationUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize", |
|
|
|
TokenUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token", |
|
|
|
Scopes = new Dictionary<string, string>() |
|
|
|
{ |
|
|
|
{ "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" } |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
options.OperationFilter<AuthorizeCheckOperationFilter>(); |
|
|
|
}); |
|
|
|
|
|
|
|
services.AddCors(options => |
|
|
|
{ |
|
|
|
options.AddPolicy("CorsPolicy", |
|
|
|
builder => builder.AllowAnyOrigin() |
|
|
|
.AllowAnyMethod() |
|
|
|
.AllowAnyHeader() |
|
|
|
.AllowCredentials()); |
|
|
|
}); |
|
|
|
|
|
|
|
return services; |
|
|
|
} |
|
|
|
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) |
|
|
|
{ |
|
|
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); |
|
|
|
var identityUrl = configuration.GetValue<string>("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.Events = new JwtBearerEvents() |
|
|
|
{ |
|
|
|
OnAuthenticationFailed = async ctx => |
|
|
|
{ |
|
|
|
int i = 0; |
|
|
|
}, |
|
|
|
OnTokenValidated = async ctx => |
|
|
|
{ |
|
|
|
int i = 0; |
|
|
|
} |
|
|
|
}; |
|
|
|
}); |
|
|
|
|
|
|
|
return services; |
|
|
|
} |
|
|
|
public static IServiceCollection AddHttpServices(this IServiceCollection services) |
|
|
|
{ |
|
|
|
//register delegating handlers
|
|
|
|
services.AddTransient<HttpClientAuthorizationDelegatingHandler>(); |
|
|
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); |
|
|
|
|
|
|
|
//register http services
|
|
|
|
services.AddHttpClient<IBasketService, BasketService>() |
|
|
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>() |
|
|
|
.AddPolicyHandler(GetRetryPolicy()) |
|
|
|
.AddPolicyHandler(GetCircuitBreakerPolicy()); |
|
|
|
|
|
|
|
services.AddHttpClient<ICatalogService, CatalogService>() |
|
|
|
.AddPolicyHandler(GetRetryPolicy()) |
|
|
|
.AddPolicyHandler(GetCircuitBreakerPolicy()); |
|
|
|
|
|
|
|
services.AddHttpClient<IOrderApiClient, OrderApiClient>() |
|
|
|
.AddPolicyHandler(GetRetryPolicy()) |
|
|
|
.AddPolicyHandler(GetCircuitBreakerPolicy()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return services; |
|
|
|
} |
|
|
|
|
|
|
|
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() |
|
|
|
{ |
|
|
|
return HttpPolicyExtensions |
|
|
|
.HandleTransientHttpError() |
|
|
|
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) |
|
|
|
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); |
|
|
|
|
|
|
|
} |
|
|
|
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy() |
|
|
|
{ |
|
|
|
return HttpPolicyExtensions |
|
|
|
.HandleTransientHttpError() |
|
|
|
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); |
|
|
|
} |
|
|
|
} |
|
|
|
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.AddCustomMvc(Configuration) |
|
|
|
.AddCustomAuthentication(Configuration) |
|
|
|
.AddHttpServices(); |
|
|
|
} |
|
|
|
|
|
|
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
|
|
|
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) |
|
|
|
{ |
|
|
|
var pathBase = Configuration["PATH_BASE"]; |
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(pathBase)) |
|
|
|
{ |
|
|
|
loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); |
|
|
|
app.UsePathBase(pathBase); |
|
|
|
} |
|
|
|
|
|
|
|
app.UseCors("CorsPolicy"); |
|
|
|
|
|
|
|
if (env.IsDevelopment()) |
|
|
|
{ |
|
|
|
app.UseDeveloperExceptionPage(); |
|
|
|
} |
|
|
|
|
|
|
|
app.UseAuthentication(); |
|
|
|
|
|
|
|
app.UseMvc(); |
|
|
|
|
|
|
|
app.UseSwagger().UseSwaggerUI(c => |
|
|
|
{ |
|
|
|
c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Purchase BFF V1"); |
|
|
|
c.ConfigureOAuth2("Microsoft.eShopOnContainers.Mobile.Shopping.HttpAggregatorwaggerui", "", "", "Purchase BFF Swagger UI"); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public static class ServiceCollectionExtensions |
|
|
|
{ |
|
|
|
public static IServiceCollection AddCustomMvc(this IServiceCollection services, IConfiguration configuration) |
|
|
|
{ |
|
|
|
services.AddOptions(); |
|
|
|
services.Configure<UrlsConfig>(configuration.GetSection("urls")); |
|
|
|
|
|
|
|
services.AddMvc().SetCompatibilityVersion(AspNetCore.Mvc.CompatibilityVersion.Version_2_1); |
|
|
|
|
|
|
|
services.AddSwaggerGen(options => |
|
|
|
{ |
|
|
|
options.DescribeAllEnumsAsStrings(); |
|
|
|
options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info |
|
|
|
{ |
|
|
|
Title = "Shopping Aggregator for Mobile Clients", |
|
|
|
Version = "v1", |
|
|
|
Description = "Shopping Aggregator for Mobile Clients", |
|
|
|
TermsOfService = "Terms Of Service" |
|
|
|
}); |
|
|
|
|
|
|
|
options.AddSecurityDefinition("oauth2", new OAuth2Scheme |
|
|
|
{ |
|
|
|
Type = "oauth2", |
|
|
|
Flow = "implicit", |
|
|
|
AuthorizationUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/authorize", |
|
|
|
TokenUrl = $"{configuration.GetValue<string>("IdentityUrlExternal")}/connect/token", |
|
|
|
Scopes = new Dictionary<string, string>() |
|
|
|
{ |
|
|
|
{ "mobileshoppingagg", "Shopping Aggregator for Mobile Clients" } |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
options.OperationFilter<AuthorizeCheckOperationFilter>(); |
|
|
|
}); |
|
|
|
|
|
|
|
services.AddCors(options => |
|
|
|
{ |
|
|
|
options.AddPolicy("CorsPolicy", |
|
|
|
builder => builder.AllowAnyOrigin() |
|
|
|
.AllowAnyMethod() |
|
|
|
.AllowAnyHeader() |
|
|
|
.AllowCredentials()); |
|
|
|
}); |
|
|
|
|
|
|
|
return services; |
|
|
|
} |
|
|
|
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) |
|
|
|
{ |
|
|
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); |
|
|
|
var identityUrl = configuration.GetValue<string>("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.Events = new JwtBearerEvents() |
|
|
|
{ |
|
|
|
OnAuthenticationFailed = async ctx => |
|
|
|
{ |
|
|
|
int i = 0; |
|
|
|
}, |
|
|
|
OnTokenValidated = async ctx => |
|
|
|
{ |
|
|
|
int i = 0; |
|
|
|
} |
|
|
|
}; |
|
|
|
}); |
|
|
|
|
|
|
|
return services; |
|
|
|
} |
|
|
|
public static IServiceCollection AddHttpServices(this IServiceCollection services) |
|
|
|
{ |
|
|
|
//register delegating handlers
|
|
|
|
services.AddTransient<HttpClientAuthorizationDelegatingHandler>(); |
|
|
|
services.AddHttpContextAccessor(); |
|
|
|
|
|
|
|
//register http services
|
|
|
|
services.AddHttpClient<IBasketService, BasketService>() |
|
|
|
.AddHttpMessageHandler<HttpClientAuthorizationDelegatingHandler>() |
|
|
|
.AddPolicyHandler(GetRetryPolicy()) |
|
|
|
.AddPolicyHandler(GetCircuitBreakerPolicy()); |
|
|
|
|
|
|
|
services.AddHttpClient<ICatalogService, CatalogService>() |
|
|
|
.AddPolicyHandler(GetRetryPolicy()) |
|
|
|
.AddPolicyHandler(GetCircuitBreakerPolicy()); |
|
|
|
|
|
|
|
services.AddHttpClient<IOrderApiClient, OrderApiClient>() |
|
|
|
.AddPolicyHandler(GetRetryPolicy()) |
|
|
|
.AddPolicyHandler(GetCircuitBreakerPolicy()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return services; |
|
|
|
} |
|
|
|
|
|
|
|
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() |
|
|
|
{ |
|
|
|
return HttpPolicyExtensions |
|
|
|
.HandleTransientHttpError() |
|
|
|
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) |
|
|
|
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); |
|
|
|
|
|
|
|
} |
|
|
|
static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy() |
|
|
|
{ |
|
|
|
return HttpPolicyExtensions |
|
|
|
.HandleTransientHttpError() |
|
|
|
.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |