diff --git a/src/Infrastructure/BotSharp.Logger/BotSharpLoggerExtensions.cs b/src/Infrastructure/BotSharp.Logger/BotSharpLoggerExtensions.cs index 4e98fd7f6..c57afb5f2 100644 --- a/src/Infrastructure/BotSharp.Logger/BotSharpLoggerExtensions.cs +++ b/src/Infrastructure/BotSharp.Logger/BotSharpLoggerExtensions.cs @@ -2,6 +2,12 @@ namespace BotSharp.Logger; public static class BotSharpLoggerExtensions { + /// + /// BotSharp conversation log + /// + /// + /// + /// public static IServiceCollection AddBotSharpLogger(this IServiceCollection services, IConfiguration config) { services.AddScoped(); diff --git a/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs b/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs index 44194444e..9fbff43a7 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/BotSharpOpenApiExtensions.cs @@ -1,28 +1,117 @@ +using BotSharp.Abstraction.Messaging.JsonConverters; +using BotSharp.Core.Users.Services; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; namespace BotSharp.OpenAPI; public static class BotSharpOpenApiExtensions { + private static string policy = "BotSharpCorsPolicy"; + /// + /// Add Swagger/OpenAPI + /// + /// + /// + /// + public static IServiceCollection AddBotSharpOpenAPI(this IServiceCollection services, + IConfiguration config, + string[] origins, + IHostEnvironment env, + bool enableValidation) + { + services.AddScoped(); + + // Add bearer authentication + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; + }).AddJwtBearer(o => + { + o.TokenValidationParameters = new TokenValidationParameters + { + ValidIssuer = config["Jwt:Issuer"], + ValidAudience = config["Jwt:Audience"], + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Jwt:Key"])), + ValidateIssuer = enableValidation, + ValidateAudience = enableValidation, + ValidateLifetime = enableValidation, + ValidateIssuerSigningKey = enableValidation + }; + + if (!enableValidation) + { + o.TokenValidationParameters.SignatureValidator = (string token, TokenValidationParameters parameters) => + new JwtSecurityToken(token); + } + }); + + // Add services to the container. + services.AddControllers() + .AddJsonOptions(options => + { + options.JsonSerializerOptions.Converters.Add(new RichContentJsonConverter()); + options.JsonSerializerOptions.Converters.Add(new TemplateMessageJsonConverter()); + }); + + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + services.AddEndpointsApiExplorer(); + services.AddSwaggerGen(); + + services.AddHttpContextAccessor(); + + services.AddCors(options => + { + options.AddPolicy(policy, + builder => builder.WithOrigins(origins) + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials()); + }); + + return services; + } + /// /// Use Swagger/OpenAPI /// /// /// /// - public static IApplicationBuilder UseBotSharpOpenAPI(this IApplicationBuilder app, bool isDevelopment = false) + public static IApplicationBuilder UseBotSharpOpenAPI(this IApplicationBuilder app, IHostEnvironment env) { if (app == null) { throw new ArgumentNullException(nameof(app)); } + app.UseCors(policy); + app.UseSwagger(); - if (isDevelopment) + if (env.IsDevelopment()) { app.UseSwaggerUI(); + app.UseDeveloperExceptionPage(); } + app.UseAuthentication(); + + app.UseRouting(); + + app.UseAuthorization(); + + app.UseEndpoints( + endpoints => + { + endpoints.MapDefaultControllerRoute(); + }); + return app; } @@ -42,6 +131,14 @@ public static IApplicationBuilder UseBotSharpUI(this IApplicationBuilder app, bo // app.UseFileServer(); app.UseDefaultFiles(); app.UseStaticFiles(); + + app.UseEndpoints( + endpoints => + { + // For SPA static file routing + endpoints.MapFallbackToFile("/index.html"); + }); + app.UseSpa(config => { if (isDevelopment) diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubServiceExtensions.cs b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubServiceExtensions.cs deleted file mode 100644 index c67685e5d..000000000 --- a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubServiceExtensions.cs +++ /dev/null @@ -1,51 +0,0 @@ -using BotSharp.Abstraction.Messaging.JsonConverters; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Configuration; - -namespace BotSharp.Plugin.ChatHub; - -public static class ChatHubServiceExtensions -{ - /// - /// Add Swagger/OpenAPI - /// - /// - /// - /// - public static IServiceCollection AddBotSharpOpenAPI(this IServiceCollection services, IConfiguration config) - { - // Add services to the container. - services.AddControllers() - .AddJsonOptions(options => - { - options.JsonSerializerOptions.Converters.Add(new RichContentJsonConverter()); - options.JsonSerializerOptions.Converters.Add(new TemplateMessageJsonConverter()); - }); - - // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle - services.AddEndpointsApiExplorer(); - services.AddSwaggerGen(); - - services.AddHttpContextAccessor(); - - return services; - } - - /// - /// Host BotSharp UI built in adapter-static - /// - /// - /// - /// - public static IApplicationBuilder UseChatHub(this IApplicationBuilder app) - { - if (app == null) - { - throw new ArgumentNullException(nameof(app)); - } - - app.UseMiddleware(); - - return app; - } -} diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/SignalRHub.cs b/src/Plugins/BotSharp.Plugin.ChatHub/SignalRHub.cs index f11bbc822..0593b94f9 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/SignalRHub.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/SignalRHub.cs @@ -49,9 +49,4 @@ public override async Task OnConnectedAsync() await base.OnConnectedAsync(); } - - public Task PushEventLog(string message) - { - return Task.CompletedTask; - } } diff --git a/src/WebStarter/Program.cs b/src/WebStarter/Program.cs index 718504883..419f5b90b 100644 --- a/src/WebStarter/Program.cs +++ b/src/WebStarter/Program.cs @@ -1,18 +1,13 @@ -using BotSharp.Abstraction.Users; using BotSharp.Core; using BotSharp.OpenAPI; -using BotSharp.Core.Users.Services; using BotSharp.Logger; using BotSharp.Plugin.ChatHub; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.IdentityModel.Tokens; -using System.Text; using Serilog; var builder = WebApplication.CreateBuilder(args); -var loggerConfig = new LoggerConfiguration(); -Log.Logger = loggerConfig +// Use Serilog +Log.Logger = new LoggerConfiguration() #if DEBUG .MinimumLevel.Debug() #else @@ -23,62 +18,28 @@ .CreateLogger(); builder.Host.UseSerilog(); -builder.Services.AddScoped(); -// Add bearer authentication -builder.Services.AddAuthentication(options => -{ - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; -}).AddJwtBearer(o => -{ - o.TokenValidationParameters = new TokenValidationParameters - { - ValidIssuer = builder.Configuration["Jwt:Issuer"], - ValidAudience = builder.Configuration["Jwt:Audience"], - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])), - ValidateIssuer = true, - ValidateAudience = true, - ValidateLifetime = false, - ValidateIssuerSigningKey = true - }; -}); - // Add BotSharp -builder.Services.AddBotSharpCore(builder.Configuration); -builder.Services.AddBotSharpOpenAPI(builder.Configuration); -builder.Services.AddBotSharpLogger(builder.Configuration); - -builder.Services.AddCors(options => -{ - options.AddPolicy("MyCorsPolicy", - builder => builder.WithOrigins("http://localhost:5015", - "http://localhost:5500", - "https://botsharp.scisharpstack.org", - "https://chat.scisharpstack.org") - .AllowAnyMethod() - .AllowAnyHeader() - .AllowCredentials()); -}); +builder.Services.AddBotSharpCore(builder.Configuration) + .AddBotSharpOpenAPI(builder.Configuration, new[] + { + "http://localhost:5015", + "https://botsharp.scisharpstack.org", + "https://chat.scisharpstack.org" + }, builder.Environment, true) + .AddBotSharpLogger(builder.Configuration); +// Add SignalR for WebSocket builder.Services.AddSignalR(); var app = builder.Build(); -// Configure the HTTP request pipeline. +// Enable SignalR app.MapHub("/chatHub"); -app.UseChatHub(); - -app.UseAuthentication(); -app.UseAuthorization(); - -app.MapControllers(); +app.UseMiddleware(); // Use BotSharp -app.UseBotSharp(); -app.UseBotSharpOpenAPI(); -app.UseBotSharpUI(); - -app.UseCors("MyCorsPolicy"); +app.UseBotSharp() + .UseBotSharpOpenAPI(app.Environment) + .UseBotSharpUI(); app.Run();