You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
279 lines
9.0 KiB
279 lines
9.0 KiB
using AX.WebDrillServer.Data; |
|
using AX.WebDrillServer.EntityMappers; |
|
using AX.WebDrillServer.Errors; |
|
using AX.WebDrillServer.Extensions; |
|
using AX.WebDrillServer.Hubs; |
|
using AX.WebDrillServer.Middlewares; |
|
using AX.WebDrillServer.Middlewares.Jwts; |
|
using AX.WebDrillServer.Services.FireDeductionHub; |
|
using Microsoft.AspNetCore.Authentication.JwtBearer; |
|
using Microsoft.AspNetCore.Mvc.Authorization; |
|
using Microsoft.AspNetCore.Mvc.Formatters; |
|
using Microsoft.AspNetCore.SignalR; |
|
using Microsoft.EntityFrameworkCore; |
|
using Microsoft.IdentityModel.Tokens; |
|
using Microsoft.OpenApi.Models; |
|
using System.IdentityModel.Tokens.Jwt; |
|
using System.Reflection; |
|
using System.Text; |
|
using System.Text.Json; |
|
using System.Text.Json.Serialization; |
|
|
|
const string ProductName = "沙盘推演"; |
|
const string ProductVersion = "v1.0"; |
|
const string ApiVersion = "v1"; |
|
|
|
#region Banner |
|
|
|
var banners = "Banners"; |
|
if (Directory.Exists(banners)) |
|
{ |
|
var files = Directory.GetFiles(banners); |
|
var random = new Random(); |
|
var file = files[random.Next(0, files.Length)]; |
|
var banner = File.ReadAllText(file); |
|
|
|
Console.ForegroundColor = ConsoleColor.Yellow; |
|
Console.Write(banner); |
|
Console.WriteLine("\n\n"); |
|
} |
|
|
|
Console.ForegroundColor = ConsoleColor.Green; |
|
Console.WriteLine("按 CTRL+C 键退出程序...\n\n"); |
|
Console.ForegroundColor = ConsoleColor.White; |
|
Console.Title = $"{ProductName} {ProductVersion}"; |
|
|
|
#endregion Banner |
|
|
|
#region ServerLicense |
|
|
|
if (!ServerLicense.Initialize()) |
|
{ |
|
Console.ForegroundColor = ConsoleColor.Red; |
|
Console.WriteLine(GlobalErrorCodes.Messages[GlobalErrorCodes.E600]); |
|
Console.WriteLine("\n\n"); |
|
} |
|
|
|
#endregion ServerLicense |
|
|
|
var builder = WebApplication.CreateBuilder(args); |
|
|
|
#region Identities |
|
|
|
builder.Services.Configure<JwtOptions>(builder.Configuration.GetSection("JwtSettings")); |
|
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); |
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) |
|
.AddJwtBearer(options => |
|
{ |
|
var secret = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JwtSettings:Secret"])); |
|
|
|
options.TokenValidationParameters = new TokenValidationParameters |
|
{ |
|
NameClaimType = JwtClaimTypes.Name, |
|
RoleClaimType = JwtClaimTypes.Role, |
|
|
|
ValidateIssuer = true, |
|
ValidIssuer = builder.Configuration["JwtSettings:Issuer"], |
|
ValidateIssuerSigningKey = true, |
|
IssuerSigningKey = secret, |
|
ValidateAudience = true, |
|
ValidAudience = builder.Configuration["JwtSettings:Audience"], |
|
RequireExpirationTime = true, |
|
ValidateLifetime = true, |
|
ClockSkew = TimeSpan.FromSeconds(30) |
|
}; |
|
|
|
// SignalR Jwt |
|
options.Events = new JwtBearerEvents |
|
{ |
|
OnMessageReceived = context => |
|
{ |
|
var accessToken = context.Request.Query["access_token"]; |
|
|
|
var path = context.HttpContext.Request.Path; |
|
if (accessToken.HasValue() && |
|
path.StartsWithSegments("/hubs")) |
|
context.Token = accessToken; |
|
|
|
return Task.CompletedTask; |
|
} |
|
}; |
|
}); |
|
|
|
builder.Services.AddSingleton<IJwtService, JwtService>(); |
|
builder.Services.AddSingleton<IUserIdProvider, NameUserIdProvider>(); |
|
|
|
builder.Services.AddAuthorization(); |
|
|
|
#endregion Identities |
|
|
|
// Email Service |
|
//builder.Services.AddSingleton<IEmailService, EmailService>(); |
|
builder.Services.AddSingleton<RoomManager>(); |
|
builder.Services.AddMemoryCache(); |
|
|
|
builder.Services |
|
.AddSignalR(options => |
|
{ |
|
#if !RELEASE |
|
options.EnableDetailedErrors = true; |
|
#endif |
|
}) |
|
.AddJsonProtocol(options => |
|
{ |
|
options.PayloadSerializerOptions.PropertyNameCaseInsensitive = true; |
|
options.PayloadSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; |
|
options.PayloadSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase; |
|
//全局配置signalr json 转枚举使用stringName还是intValue |
|
options.PayloadSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); |
|
}); |
|
|
|
//#region Custom Services |
|
|
|
//builder.Services.AddTransient<INotificationService, NotificationService>(); |
|
|
|
//#endregion Custom Services |
|
|
|
builder.Services |
|
.AddControllers(options => |
|
{ |
|
options.InputFormatters.Insert(0, new RawJsonInputFormatter()); |
|
options.OutputFormatters.Insert(0, new RawJsonOutputFormatter()); |
|
//options.Filters.Add(new AuthorizeFilter()); |
|
}) |
|
.AddJsonOptions(options => |
|
{ |
|
options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; |
|
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; |
|
options.JsonSerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase; |
|
//全局配置Controller json 转枚举使用stringName还是intValue |
|
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); |
|
}); |
|
|
|
builder.Services.AddEndpointsApiExplorer(); |
|
|
|
#region Swagger |
|
|
|
if (builder.Environment.IsDevelopment() || builder.Environment.IsStaging()) |
|
{ |
|
builder.Services.AddSwaggerGen(options => |
|
{ |
|
options.CustomSchemaIds(type => type.ToString()); |
|
options.SwaggerDoc(ApiVersion, new OpenApiInfo { Title = $"{ProductName} API", Version = ApiVersion }); |
|
|
|
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; |
|
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); |
|
|
|
options.IncludeXmlComments(xmlPath, true); |
|
options.IgnoreObsoleteActions(); |
|
|
|
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme |
|
{ |
|
Description = "使用 JWT Bearer 模式进行授权。示例: \"Bearer {token}\"", |
|
Name = "Authorization", //Jwt default param name |
|
In = ParameterLocation.Header, //Jwt store address |
|
Type = SecuritySchemeType.ApiKey, //Security scheme type |
|
Scheme = "Bearer", |
|
BearerFormat = "JWT" |
|
}); |
|
|
|
options.AddSecurityRequirement(new OpenApiSecurityRequirement |
|
{ |
|
{ |
|
new OpenApiSecurityScheme |
|
{ |
|
Reference = new OpenApiReference |
|
{ |
|
Type = ReferenceType.SecurityScheme, |
|
Id = "Bearer" |
|
}, |
|
}, |
|
Array.Empty<string>() |
|
} |
|
}); |
|
|
|
// File Filter |
|
options.OperationFilter<FileUploadOperationFilter>(); |
|
}); |
|
} |
|
|
|
#endregion Swagger |
|
|
|
#region Database Context |
|
|
|
|
|
builder.Services.AddDbContextPool<ApplicationDbContext>((provider, options) => |
|
{ |
|
if (builder.Environment.IsDevelopment() || builder.Environment.IsStaging()) |
|
options.EnableSensitiveDataLogging(); |
|
options.UseNpgsql(builder.Configuration.GetConnectionString("PostgreSQL"), |
|
// 全局启用拆分查询, 详见: https://docs.microsoft.com/zh-cn/ef/core/querying/single-split-queries; |
|
opts => opts.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)); |
|
|
|
}); |
|
|
|
#endregion Database Context |
|
|
|
#region Mapper |
|
|
|
EntityMapperConfig.Initialize(); |
|
|
|
#endregion Mapper |
|
|
|
var app = builder.Build(); |
|
|
|
#region Setup Database |
|
|
|
app.SetupDatabase(); |
|
|
|
#endregion Setup Database |
|
|
|
#region Development |
|
|
|
if (app.Environment.IsDevelopment() || app.Environment.IsStaging()) |
|
{ |
|
app.UseDeveloperExceptionPage(); |
|
app.UseSwagger(); |
|
app.UseSwaggerUI(options => |
|
{ |
|
options.SwaggerEndpoint($"/swagger/{ApiVersion}/swagger.json", $"{ProductName} API {ApiVersion}"); |
|
options.EnablePersistAuthorization(); |
|
}); |
|
app.UseReDoc(options => |
|
{ |
|
options.RoutePrefix = "docs"; |
|
options.DocumentTitle = $"{ProductName} API {ApiVersion}"; |
|
|
|
options.SpecUrl($"/swagger/{ApiVersion}/swagger.json"); |
|
options.EnableUntrustedSpec(); |
|
options.ScrollYOffset(10); |
|
options.HideHostname(); |
|
options.HideDownloadButton(); |
|
options.ExpandResponses("200,201"); |
|
options.RequiredPropsFirst(); |
|
//c.NoAutoAuth(); |
|
//c.PathInMiddlePanel(); |
|
//c.HideLoading(); |
|
//c.NativeScrollbars(); |
|
//c.DisableSearch(); |
|
//c.OnlyRequiredInSamples(); |
|
//c.SortPropsAlphabetically(); |
|
}); |
|
|
|
app.UseHttpLogging(); |
|
} |
|
|
|
#endregion Development |
|
|
|
//app.UseHttpsRedirection(); |
|
|
|
app.UseAuthentication(); |
|
app.UseAuthorization(); |
|
|
|
app.MapControllers(); |
|
|
|
//app.MapHub<NotificationHub>("/hubs/notification"); |
|
//app.MapHub<TaskChatHub>("/hubs/taskchat"); |
|
app.MapHub<FireDeductionHub>("/hubs/FireDeductionHub"); |
|
|
|
app.Run(); |