@ -1,11 +0,0 @@ | |||||
namespace Webhooks.API.Controllers; | |||||
public class HomeController : Controller | |||||
{ | |||||
// GET: /<controller>/ | |||||
public IActionResult Index() | |||||
{ | |||||
return new RedirectResult("~/swagger"); | |||||
} | |||||
} |
@ -0,0 +1,47 @@ | |||||
internal static class CustomExtensionMethods | |||||
{ | |||||
public static IServiceCollection AddDbContexts(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddDbContext<WebhooksContext>(options => | |||||
{ | |||||
options.UseSqlServer(configuration.GetRequiredConnectionString("WebHooksDb"), | |||||
sqlServerOptionsAction: sqlOptions => | |||||
{ | |||||
sqlOptions.MigrationsAssembly(typeof(Program).Assembly.FullName); | |||||
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency | |||||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); | |||||
}); | |||||
}); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
var hcBuilder = services.AddHealthChecks(); | |||||
hcBuilder | |||||
.AddSqlServer(_ => | |||||
configuration.GetRequiredConnectionString("WebHooksDb"), | |||||
name: "WebhooksApiDb-check", | |||||
tags: new string[] { "ready", "live" }); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddHttpClientServices(this IServiceCollection services) | |||||
{ | |||||
// Add http client services | |||||
services.AddHttpClient("GrantClient") | |||||
.SetHandlerLifetime(TimeSpan.FromMinutes(5)); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddIntegrationServices(this IServiceCollection services) | |||||
{ | |||||
return services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>( | |||||
sp => (DbConnection c) => new IntegrationEventLogService(c)); | |||||
} | |||||
} |
@ -1,46 +1,28 @@ | |||||
global using HealthChecks.UI.Client; | |||||
global using Microsoft.AspNetCore.Authentication.JwtBearer; | |||||
global using System; | |||||
global using System.Collections.Generic; | |||||
global using System.ComponentModel.DataAnnotations; | |||||
global using System.Data.Common; | |||||
global using System.Linq; | |||||
global using System.Net; | |||||
global using System.Net.Http; | |||||
global using System.Text; | |||||
global using System.Text.Json; | |||||
global using System.Threading.Tasks; | |||||
global using Microsoft.AspNetCore.Authorization; | global using Microsoft.AspNetCore.Authorization; | ||||
global using Microsoft.AspNetCore.Builder; | global using Microsoft.AspNetCore.Builder; | ||||
global using Microsoft.AspNetCore.Diagnostics.HealthChecks; | |||||
global using Microsoft.AspNetCore.Hosting; | global using Microsoft.AspNetCore.Hosting; | ||||
global using Microsoft.AspNetCore.Http; | global using Microsoft.AspNetCore.Http; | ||||
global using Microsoft.AspNetCore.Mvc.Filters; | |||||
global using Microsoft.AspNetCore.Mvc; | global using Microsoft.AspNetCore.Mvc; | ||||
global using Microsoft.AspNetCore; | |||||
global using Microsoft.EntityFrameworkCore.Design; | |||||
global using Microsoft.EntityFrameworkCore; | global using Microsoft.EntityFrameworkCore; | ||||
global using Microsoft.EntityFrameworkCore.Design; | |||||
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; | ||||
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Events; | ||||
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; | |||||
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; | |||||
global using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; | |||||
global using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; | global using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; | ||||
global using Microsoft.Extensions.Configuration; | global using Microsoft.Extensions.Configuration; | ||||
global using Microsoft.Extensions.DependencyInjection; | 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.Logging; | ||||
global using Microsoft.OpenApi.Models; | |||||
global using RabbitMQ.Client; | |||||
global using Swashbuckle.AspNetCore.SwaggerGen; | |||||
global using System.Collections.Generic; | |||||
global using System.ComponentModel.DataAnnotations; | |||||
global using System.Data.Common; | |||||
global using System.IdentityModel.Tokens.Jwt; | |||||
global using System.Linq; | |||||
global using System.Net.Http; | |||||
global using System.Net; | |||||
global using System.Reflection; | |||||
global using System.Text.Json; | |||||
global using System.Text; | |||||
global using System.Threading.Tasks; | |||||
global using System.Threading; | |||||
global using System; | |||||
global using Webhooks.API.Exceptions; | |||||
global using Webhooks.API.Infrastructure.ActionResult; | |||||
global using Services.Common; | |||||
global using Webhooks.API.Infrastructure; | global using Webhooks.API.Infrastructure; | ||||
global using Webhooks.API.IntegrationEvents; | global using Webhooks.API.IntegrationEvents; | ||||
global using Webhooks.API.Model; | global using Webhooks.API.Model; | ||||
global using Webhooks.API.Services; | global using Webhooks.API.Services; | ||||
global using Webhooks.API; |
@ -1,9 +0,0 @@ | |||||
namespace Webhooks.API.Infrastructure.ActionResult; | |||||
class InternalServerErrorObjectResult : ObjectResult | |||||
{ | |||||
public InternalServerErrorObjectResult(object error) : base(error) | |||||
{ | |||||
StatusCode = StatusCodes.Status500InternalServerError; | |||||
} | |||||
} |
@ -1,29 +0,0 @@ | |||||
namespace Webhooks.API.Infrastructure; | |||||
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 [] { "webhooksapi" } | |||||
} | |||||
}; | |||||
} | |||||
} |
@ -1,58 +0,0 @@ | |||||
namespace Webhooks.API.Infrastructure; | |||||
public class HttpGlobalExceptionFilter : IExceptionFilter | |||||
{ | |||||
private readonly IWebHostEnvironment _env; | |||||
private readonly ILogger<HttpGlobalExceptionFilter> _logger; | |||||
public HttpGlobalExceptionFilter(IWebHostEnvironment env, ILogger<HttpGlobalExceptionFilter> logger) | |||||
{ | |||||
_env = env; | |||||
_logger = logger; | |||||
} | |||||
public void OnException(ExceptionContext context) | |||||
{ | |||||
_logger.LogError(new EventId(context.Exception.HResult), | |||||
context.Exception, | |||||
context.Exception.Message); | |||||
if (context.Exception.GetType() == typeof(WebhooksDomainException)) | |||||
{ | |||||
var problemDetails = new ValidationProblemDetails() | |||||
{ | |||||
Instance = context.HttpContext.Request.Path, | |||||
Status = StatusCodes.Status400BadRequest, | |||||
Detail = "Please refer to the errors property for additional details." | |||||
}; | |||||
problemDetails.Errors.Add("DomainValidations", new[] { context.Exception.Message }); | |||||
context.Result = new BadRequestObjectResult(problemDetails); | |||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; | |||||
} | |||||
else | |||||
{ | |||||
var json = new JsonErrorResponse | |||||
{ | |||||
Messages = new[] { "An error occurred." } | |||||
}; | |||||
if (_env.IsDevelopment()) | |||||
{ | |||||
json.DeveloperMessage = context.Exception; | |||||
} | |||||
context.Result = new InternalServerErrorObjectResult(json); | |||||
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; | |||||
} | |||||
context.ExceptionHandled = true; | |||||
} | |||||
private class JsonErrorResponse | |||||
{ | |||||
public string[] Messages { get; set; } | |||||
public object DeveloperMessage { get; set; } | |||||
} | |||||
} |
@ -1,20 +1,41 @@ | |||||
// TODO: Don't do this twice... | |||||
var host = CreateWebHostBuilder(args).Build(); | |||||
host.Services.MigrateDbContext<WebhooksContext>((_, __) => { }); | |||||
host.Run(); | |||||
IWebHostBuilder CreateWebHostBuilder(string[] args) => | |||||
WebHost.CreateDefaultBuilder(args) | |||||
.UseStartup<Startup>() | |||||
.ConfigureAppConfiguration((builderContext, config) => | |||||
{ | |||||
config.AddEnvironmentVariables(); | |||||
}) | |||||
.ConfigureLogging((hostingContext, builder) => | |||||
{ | |||||
builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); | |||||
builder.AddConsole(); | |||||
builder.AddDebug(); | |||||
builder.AddAzureWebAppDiagnostics(); | |||||
}); | |||||
var builder = WebApplication.CreateBuilder(args); | |||||
builder.AddServiceDefaults(); | |||||
builder.Services.AddControllers(); | |||||
builder.Services.AddDbContexts(builder.Configuration); | |||||
builder.Services.AddHealthChecks(builder.Configuration); | |||||
builder.Services.AddHttpClientServices(); | |||||
builder.Services.AddIntegrationServices(); | |||||
builder.Services.AddTransient<IIdentityService, IdentityService>(); | |||||
builder.Services.AddTransient<IGrantUrlTesterService, GrantUrlTesterService>(); | |||||
builder.Services.AddTransient<IWebhooksRetriever, WebhooksRetriever>(); | |||||
builder.Services.AddTransient<IWebhooksSender, WebhooksSender>(); | |||||
builder.Services.AddTransient<ProductPriceChangedIntegrationEventHandler>(); | |||||
builder.Services.AddTransient<OrderStatusChangedToShippedIntegrationEventHandler>(); | |||||
builder.Services.AddTransient<OrderStatusChangedToPaidIntegrationEventHandler>(); | |||||
var app = builder.Build(); | |||||
if (!await app.CheckHealthAsync()) | |||||
{ | |||||
return; | |||||
} | |||||
app.UseServiceDefaults(); | |||||
app.MapGet("/", () => Results.Redirect("/swagger")); | |||||
app.MapControllers(); | |||||
var eventBus = app.Services.GetRequiredService<IEventBus>(); | |||||
eventBus.Subscribe<ProductPriceChangedIntegrationEvent, ProductPriceChangedIntegrationEventHandler>(); | |||||
eventBus.Subscribe<OrderStatusChangedToShippedIntegrationEvent, OrderStatusChangedToShippedIntegrationEventHandler>(); | |||||
eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent, OrderStatusChangedToPaidIntegrationEventHandler>(); | |||||
app.Services.MigrateDbContext<WebhooksContext>((_, __) => { }); | |||||
await app.RunAsync(); |
@ -1,318 +0,0 @@ | |||||
namespace Webhooks.API; | |||||
public class Startup | |||||
{ | |||||
public IConfiguration Configuration { get; } | |||||
public Startup(IConfiguration configuration) | |||||
{ | |||||
Configuration = configuration; | |||||
} | |||||
public IServiceProvider ConfigureServices(IServiceCollection services) | |||||
{ | |||||
services | |||||
.AddAppInsight(Configuration) | |||||
.AddCustomRouting(Configuration) | |||||
.AddCustomDbContext(Configuration) | |||||
.AddSwagger(Configuration) | |||||
.AddCustomHealthCheck(Configuration) | |||||
.AddHttpClientServices(Configuration) | |||||
.AddIntegrationServices(Configuration) | |||||
.AddEventBus(Configuration) | |||||
.AddCustomAuthentication(Configuration) | |||||
.AddSingleton<IHttpContextAccessor, HttpContextAccessor>() | |||||
.AddTransient<IIdentityService, IdentityService>() | |||||
.AddTransient<IGrantUrlTesterService, GrantUrlTesterService>() | |||||
.AddTransient<IWebhooksRetriever, WebhooksRetriever>() | |||||
.AddTransient<IWebhooksSender, WebhooksSender>(); | |||||
return services.BuildServiceProvider(); | |||||
} | |||||
public void Configure(IApplicationBuilder app, ILogger<Startup> logger) | |||||
{ | |||||
var pathBase = Configuration["PATH_BASE"]; | |||||
if (!string.IsNullOrEmpty(pathBase)) | |||||
{ | |||||
logger.LogDebug("Using PATH BASE '{PathBase}'", pathBase); | |||||
app.UsePathBase(pathBase); | |||||
} | |||||
app.UseRouting(); | |||||
app.UseCors("CorsPolicy"); | |||||
ConfigureAuth(app); | |||||
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") | |||||
}); | |||||
}); | |||||
app.UseSwagger() | |||||
.UseSwaggerUI(c => | |||||
{ | |||||
c.SwaggerEndpoint($"{(!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty)}/swagger/v1/swagger.json", "Webhooks.API V1"); | |||||
c.OAuthClientId("webhooksswaggerui"); | |||||
c.OAuthAppName("WebHooks Service Swagger UI"); | |||||
}); | |||||
ConfigureEventBus(app); | |||||
} | |||||
protected virtual void ConfigureAuth(IApplicationBuilder app) | |||||
{ | |||||
app.UseAuthentication(); | |||||
app.UseAuthorization(); | |||||
} | |||||
protected virtual void ConfigureEventBus(IApplicationBuilder app) | |||||
{ | |||||
var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>(); | |||||
eventBus.Subscribe<ProductPriceChangedIntegrationEvent, ProductPriceChangedIntegrationEventHandler>(); | |||||
eventBus.Subscribe<OrderStatusChangedToShippedIntegrationEvent, OrderStatusChangedToShippedIntegrationEventHandler>(); | |||||
eventBus.Subscribe<OrderStatusChangedToPaidIntegrationEvent, OrderStatusChangedToPaidIntegrationEventHandler>(); | |||||
} | |||||
} | |||||
internal static class CustomExtensionMethods | |||||
{ | |||||
public static IServiceCollection AddAppInsight(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddApplicationInsightsTelemetry(configuration); | |||||
services.AddApplicationInsightsKubernetesEnricher(); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddCustomRouting(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddControllers(options => | |||||
{ | |||||
options.Filters.Add(typeof(HttpGlobalExceptionFilter)); | |||||
}); | |||||
services.AddCors(options => | |||||
{ | |||||
options.AddPolicy("CorsPolicy", | |||||
builder => builder | |||||
.SetIsOriginAllowed((host) => true) | |||||
.AllowAnyMethod() | |||||
.AllowAnyHeader() | |||||
.AllowCredentials()); | |||||
}); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddEntityFrameworkSqlServer() | |||||
.AddDbContext<WebhooksContext>(options => | |||||
{ | |||||
options.UseSqlServer(configuration["ConnectionString"], | |||||
sqlServerOptionsAction: sqlOptions => | |||||
{ | |||||
sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); | |||||
//Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency | |||||
sqlOptions.EnableRetryOnFailure(maxRetryCount: 15, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); | |||||
}); | |||||
}); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddSwagger(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddSwaggerGen(options => | |||||
{ | |||||
options.SwaggerDoc("v1", new OpenApiInfo | |||||
{ | |||||
Title = "eShopOnContainers - Webhooks HTTP API", | |||||
Version = "v1", | |||||
Description = "The Webhooks Microservice HTTP API. This is a simple webhooks CRUD registration entrypoint" | |||||
}); | |||||
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>() | |||||
{ | |||||
{ "webhooks", "Webhooks API" } | |||||
} | |||||
} | |||||
} | |||||
}); | |||||
options.OperationFilter<AuthorizeCheckOperationFilter>(); | |||||
}); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
if (configuration.GetValue<bool>("AzureServiceBusEnabled")) | |||||
{ | |||||
services.AddSingleton<IEventBus, EventBusServiceBus>(sp => | |||||
{ | |||||
var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>(); | |||||
var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>(); | |||||
var eventBusSubscriptionManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); | |||||
string subscriptionName = configuration["SubscriptionClientName"]; | |||||
return new EventBusServiceBus(serviceBusPersisterConnection, logger, | |||||
eventBusSubscriptionManager, sp, subscriptionName); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
services.AddSingleton<IEventBus, EventBusRabbitMQ>(sp => | |||||
{ | |||||
var subscriptionClientName = configuration["SubscriptionClientName"]; | |||||
var rabbitMQPersistentConnection = sp.GetRequiredService<IRabbitMQPersistentConnection>(); | |||||
var logger = sp.GetRequiredService<ILogger<EventBusRabbitMQ>>(); | |||||
var eventBusSubscriptionManager = sp.GetRequiredService<IEventBusSubscriptionsManager>(); | |||||
var retryCount = 5; | |||||
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) | |||||
{ | |||||
retryCount = int.Parse(configuration["EventBusRetryCount"]); | |||||
} | |||||
return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, sp, eventBusSubscriptionManager, subscriptionClientName, retryCount); | |||||
}); | |||||
} | |||||
services.AddSingleton<IEventBusSubscriptionsManager, InMemoryEventBusSubscriptionsManager>(); | |||||
services.AddTransient<ProductPriceChangedIntegrationEventHandler>(); | |||||
services.AddTransient<OrderStatusChangedToShippedIntegrationEventHandler>(); | |||||
services.AddTransient<OrderStatusChangedToPaidIntegrationEventHandler>(); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
var hcBuilder = services.AddHealthChecks(); | |||||
hcBuilder | |||||
.AddCheck("self", () => HealthCheckResult.Healthy()) | |||||
.AddSqlServer( | |||||
configuration["ConnectionString"], | |||||
name: "WebhooksApiDb-check", | |||||
tags: new string[] { "webhooksdb" }); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddHttpClientServices(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); | |||||
services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(Timeout.InfiniteTimeSpan); | |||||
//add http client services | |||||
services.AddHttpClient("GrantClient") | |||||
.SetHandlerLifetime(TimeSpan.FromMinutes(5)); | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddIntegrationServices(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
services.AddTransient<Func<DbConnection, IIntegrationEventLogService>>( | |||||
sp => (DbConnection c) => new IntegrationEventLogService(c)); | |||||
if (configuration.GetValue<bool>("AzureServiceBusEnabled")) | |||||
{ | |||||
services.AddSingleton<IServiceBusPersisterConnection>(sp => | |||||
{ | |||||
var subscriptionClientName = configuration["SubscriptionClientName"]; | |||||
return new DefaultServiceBusPersisterConnection(configuration["EventBusConnection"]); | |||||
}); | |||||
} | |||||
else | |||||
{ | |||||
services.AddSingleton<IRabbitMQPersistentConnection>(sp => | |||||
{ | |||||
var logger = sp.GetRequiredService<ILogger<DefaultRabbitMQPersistentConnection>>(); | |||||
var factory = new ConnectionFactory() | |||||
{ | |||||
HostName = configuration["EventBusConnection"], | |||||
DispatchConsumersAsync = true | |||||
}; | |||||
if (!string.IsNullOrEmpty(configuration["EventBusUserName"])) | |||||
{ | |||||
factory.UserName = configuration["EventBusUserName"]; | |||||
} | |||||
if (!string.IsNullOrEmpty(configuration["EventBusPassword"])) | |||||
{ | |||||
factory.Password = configuration["EventBusPassword"]; | |||||
} | |||||
var retryCount = 5; | |||||
if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) | |||||
{ | |||||
retryCount = int.Parse(configuration["EventBusRetryCount"]); | |||||
} | |||||
return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); | |||||
}); | |||||
} | |||||
return services; | |||||
} | |||||
public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) | |||||
{ | |||||
// prevent from mapping "sub" claim to nameidentifier. | |||||
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); | |||||
var identityUrl = configuration.GetValue<string>("IdentityUrl"); | |||||
services.AddAuthentication(options => | |||||
{ | |||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; | |||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; | |||||
}).AddJwtBearer(options => | |||||
{ | |||||
options.Authority = identityUrl; | |||||
options.RequireHttpsMetadata = false; | |||||
options.Audience = "webhooks"; | |||||
options.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", "webhooks"); | |||||
}); | |||||
}); | |||||
return services; | |||||
} | |||||
} |
@ -1,10 +1,44 @@ | |||||
{ | { | ||||
"Logging": { | "Logging": { | ||||
"LogLevel": { | "LogLevel": { | ||||
"Default": "Warning" | |||||
"Default": "Information", | |||||
"Microsoft.AspNetCore": "Warning" | |||||
} | } | ||||
}, | }, | ||||
"AllowedHosts": "*", | "AllowedHosts": "*", | ||||
"SubscriptionClientName": "Webhooks", | |||||
"EventBusRetryCount": 5 | |||||
"OpenApi": { | |||||
"Endpoint": { | |||||
"Name": "Webhooks.API V1" | |||||
}, | |||||
"Document": { | |||||
"Description": "The Webhooks Microservice HTTP API. This is a simple webhooks CRUD registration entrypoint", | |||||
"Title": "eShopOnContainers - Webhooks HTTP API", | |||||
"Version": "v1" | |||||
}, | |||||
"Auth": { | |||||
"ClientId": "webhooksswaggerui", | |||||
"AppName": "WebHooks Service Swagger UI" | |||||
} | |||||
}, | |||||
"ConnectionStrings": { | |||||
"EventBus": "localhost" | |||||
}, | |||||
"EventBus": { | |||||
"SubscriptionClientName": "Webhooks", | |||||
"RetryCount": 5 | |||||
}, | |||||
"ApplicationInsights": { | |||||
"InstrumentationKey": "" | |||||
}, | |||||
"Identity": { | |||||
"Url": "http://localhost:5105", | |||||
"ExternalUrl": "http://localhost:5105", | |||||
"Audience": "webhooks", | |||||
"Scopes": { | |||||
"webhooks": "Webhooks API" | |||||
} | |||||
}, | |||||
"UseCustomizationData": false, | |||||
"GracePeriodTime": "1", | |||||
"CheckUpdateTime": "30000" | |||||
} | } |