218 lines
7.2 KiB
C#
218 lines
7.2 KiB
C#
using FluentValidation;
|
|
using Gameboard.ShogiUI.Sockets.Extensions;
|
|
using Gameboard.ShogiUI.Sockets.Managers;
|
|
using Gameboard.ShogiUI.Sockets.Managers.ClientActionHandlers;
|
|
using Gameboard.ShogiUI.Sockets.Repositories;
|
|
using Gameboard.ShogiUI.Sockets.ServiceModels.Socket;
|
|
using Gameboard.ShogiUI.Sockets.Services;
|
|
using Gameboard.ShogiUI.Sockets.Services.RequestValidators;
|
|
using Microsoft.AspNetCore.Authentication;
|
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Http;
|
|
using Microsoft.Identity.Client;
|
|
using Microsoft.Identity.Web;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Converters;
|
|
using Newtonsoft.Json.Serialization;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Security.Claims;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Gameboard.ShogiUI.Sockets
|
|
{
|
|
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.AddSingleton<IJoinByCodeHandler, JoinByCodeHandler>();
|
|
services.AddSingleton<ISocketConnectionManager, SocketConnectionManager>();
|
|
services.AddSingleton<ISocketTokenCache, SocketTokenCache>();
|
|
services.AddSingleton<IGameboardManager, GameboardManager>();
|
|
services.AddSingleton<IValidator<JoinByCodeRequest>, JoinByCodeRequestValidator>();
|
|
services.AddSingleton<IValidator<JoinGameRequest>, JoinGameRequestValidator>();
|
|
services.AddSingleton<ISocketService, SocketService>();
|
|
services.AddTransient<IGameboardRepository, GameboardRepository>();
|
|
services.AddSingleton<IClaimsTransformation, ShogiUserClaimsTransformer>();
|
|
services.AddHttpClient("couchdb", c =>
|
|
{
|
|
var base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes("admin:admin"));
|
|
c.DefaultRequestHeaders.Add("Accept", "application/json");
|
|
c.DefaultRequestHeaders.Add("Authorization", $"Basic {base64}");
|
|
|
|
var baseUrl = $"{Configuration["AppSettings:CouchDB:Url"]}/{Configuration["AppSettings:CouchDB:Database"]}/";
|
|
c.BaseAddress = new Uri(baseUrl);
|
|
});
|
|
|
|
services
|
|
.AddControllers()
|
|
.AddNewtonsoftJson(options =>
|
|
{
|
|
options.SerializerSettings.Formatting = Formatting.Indented;
|
|
options.SerializerSettings.ContractResolver = new DefaultContractResolver
|
|
{
|
|
NamingStrategy = new CamelCaseNamingStrategy { ProcessDictionaryKeys = true }
|
|
};
|
|
options.SerializerSettings.Converters = new[] { new StringEnumConverter() };
|
|
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
|
|
});
|
|
|
|
services.AddAuthentication("CookieOrJwt")
|
|
.AddPolicyScheme("CookieOrJwt", "Either cookie or jwt", options =>
|
|
{
|
|
options.ForwardDefaultSelector = context =>
|
|
{
|
|
var bearerAuth = context.Request.Headers["Authorization"].FirstOrDefault()?.StartsWith("Bearer ") ?? false;
|
|
return bearerAuth
|
|
? JwtBearerDefaults.AuthenticationScheme
|
|
: CookieAuthenticationDefaults.AuthenticationScheme;
|
|
};
|
|
})
|
|
.AddCookie(options =>
|
|
{
|
|
options.Cookie.Name = "session-id";
|
|
options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None;
|
|
options.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.Always;
|
|
options.SlidingExpiration = true;
|
|
})
|
|
.AddMicrosoftIdentityWebApi(Configuration);
|
|
|
|
services.AddSwaggerDocument(config =>
|
|
{
|
|
//config.AddSecurity("bearer", Enumerable.Empty<string>(), new NSwag.OpenApiSecurityScheme
|
|
//{
|
|
// Type = NSwag.OpenApiSecuritySchemeType.OAuth2,
|
|
// Flow = NSwag.OpenApiOAuth2Flow.Implicit,
|
|
// Flows = new NSwag.OpenApiOAuthFlows
|
|
// {
|
|
// Implicit = new NSwag.OpenApiOAuthFlow
|
|
// {
|
|
// Scopes =
|
|
// }
|
|
// }
|
|
//});
|
|
|
|
// This just ensures anyone with a microsoft account can make API calls.
|
|
config.AddSecurity("bearer", new NSwag.OpenApiSecurityScheme
|
|
{
|
|
Type = NSwag.OpenApiSecuritySchemeType.OAuth2,
|
|
Flow = NSwag.OpenApiOAuth2Flow.Implicit,
|
|
AuthorizationUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
|
|
TokenUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
|
Scopes = new Dictionary<string, string> {
|
|
{ "api://c1e94676-cab0-42ba-8b6c-9532b8486fff/access_as_user", "The scope" },
|
|
{ "api://c1e94676-cab0-42ba-8b6c-9532b8486fff/ShogiAdmin", "Admin scope" }
|
|
},
|
|
Scheme = "bearer",
|
|
BearerFormat = "JWT",
|
|
In = NSwag.OpenApiSecurityApiKeyLocation.Header,
|
|
});
|
|
config.PostProcess = document =>
|
|
{
|
|
document.Info.Title = "Gameboard.ShogiUI.Sockets";
|
|
};
|
|
});
|
|
|
|
// Remove default HttpClient logging.
|
|
services.RemoveAll<IHttpMessageHandlerBuilderFilter>();
|
|
}
|
|
|
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISocketService socketConnectionManager)
|
|
{
|
|
var origins = new[] {
|
|
"http://localhost:3000", "https://localhost:3000",
|
|
"http://127.0.0.1:3000", "https://127.0.0.1:3000",
|
|
"https://dev.lucaserver.space", "https://lucaserver.space"
|
|
};
|
|
var socketOptions = new WebSocketOptions();
|
|
foreach (var o in origins)
|
|
socketOptions.AllowedOrigins.Add(o);
|
|
|
|
if (env.IsDevelopment())
|
|
{
|
|
app.UseDeveloperExceptionPage();
|
|
var client = PublicClientApplicationBuilder
|
|
.Create(Configuration["AzureAd:ClientId"])
|
|
.WithLogging(
|
|
(level, message, pii) =>
|
|
{
|
|
Console.WriteLine(message);
|
|
},
|
|
LogLevel.Verbose,
|
|
true,
|
|
true
|
|
)
|
|
.Build();
|
|
}
|
|
else
|
|
{
|
|
app.UseHsts();
|
|
}
|
|
app
|
|
.UseRequestResponseLogging()
|
|
.UseCors(opt => opt.WithOrigins(origins).AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("Set-Cookie").AllowCredentials())
|
|
.UseRouting()
|
|
.UseAuthentication()
|
|
.UseAuthorization()
|
|
.UseOpenApi()
|
|
.UseSwaggerUi3(config =>
|
|
{
|
|
config.OAuth2Client = new NSwag.AspNetCore.OAuth2ClientSettings()
|
|
{
|
|
ClientId = "c1e94676-cab0-42ba-8b6c-9532b8486fff",
|
|
UsePkceWithAuthorizationCodeGrant = true
|
|
};
|
|
//config.WithCredentials = true;
|
|
})
|
|
.UseWebSockets(socketOptions)
|
|
.UseEndpoints(endpoints =>
|
|
{
|
|
endpoints.MapControllers();
|
|
})
|
|
.Use(async (context, next) =>
|
|
{
|
|
if (context.WebSockets.IsWebSocketRequest)
|
|
{
|
|
await socketConnectionManager.HandleSocketRequest(context);
|
|
}
|
|
else
|
|
{
|
|
await next();
|
|
}
|
|
});
|
|
|
|
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
|
|
{
|
|
Formatting = Formatting.Indented,
|
|
ContractResolver = new DefaultContractResolver
|
|
{
|
|
NamingStrategy = new CamelCaseNamingStrategy
|
|
{
|
|
ProcessDictionaryKeys = true
|
|
}
|
|
},
|
|
Converters = new[] { new StringEnumConverter() },
|
|
NullValueHandling = NullValueHandling.Ignore,
|
|
};
|
|
}
|
|
}
|
|
}
|