using Apimanager_backend.Dtos; using Apimanager_backend.Services; using Apimanager_backend.Tools; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; using Public; using StackExchange.Redis; using System.Reflection; using System.Text; using System.Threading.RateLimiting; namespace Apimanager_backend.Config { public static class ServiceCollectionExtensions { public static IServiceCollection AddAllService(this IServiceCollection services,IConfiguration configuration) { services.AddCorsService(configuration); services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); services.AddJWTService(configuration); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddApiHandler(configuration); services.AddRateLimit(configuration); return services; } public static IServiceCollection AddJWTService(this IServiceCollection services,IConfiguration configuration) { var jwtSettings = configuration.GetSection("JwtSettings"); var key = Encoding.ASCII.GetBytes(jwtSettings["Secret"]); // JWT配置 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { //jwt参数 options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = jwtSettings["Issuer"], ValidAudience = jwtSettings["Audience"], IssuerSigningKey = new SymmetricSecurityKey(key) }; //添加自定义响应处理函数 options.Events = new JwtBearerEvents { OnChallenge = new Func(JwtTokenErrorEventFunc), OnForbidden = new Func(JwtPermissionEventFunc) }; }); //redis配置 services.AddSingleton(ConnectionMultiplexer.Connect(configuration["Redis:ConnectionString"])); return services; } /// /// token无效事件处理函数 /// /// /// public async static Task JwtTokenErrorEventFunc(JwtBearerChallengeContext context) { context.Response.ContentType = "application/json"; var res = new ResponseBase( code: 1002, message: "用户未登录或认证失败", data: null ); context.Response.StatusCode = StatusCodes.Status401Unauthorized; await context.Response.WriteAsync(JsonConvert.SerializeObject(res)); context.HandleResponse(); } public async static Task JwtPermissionEventFunc(ForbiddenContext context) { context.Response.ContentType = "application/json"; var res = new ResponseBase( code: 2006, message: "用户无权限进行该操作", data: null ); context.Response.StatusCode = StatusCodes.Status401Unauthorized; await context.Response.WriteAsync(JsonConvert.SerializeObject(res)); } public static IServiceCollection AddCorsService(this IServiceCollection services,IConfiguration configuration1) { services.AddCors(option => { option.AddPolicy("AllowAll",builder => { builder.AllowAnyHeader(); builder.AllowAnyMethod(); builder.AllowAnyOrigin(); }); }); return services; } public static IServiceCollection AddApiHandler(this IServiceCollection services,IConfiguration configuration1) { /* var handlerTypes = Assembly.GetExecutingAssembly() .GetTypes() .Where(t => typeof(IBillableApiHandler).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract); foreach(var type in handlerTypes) { services.AddTransient(type); } */ services.AddSingleton(); var pluginLoaderService = services.BuildServiceProvider() .GetRequiredService(); pluginLoaderService.LoadPlugins(services); services.AddScoped(); return services; } public static IServiceCollection AddRateLimit(this IServiceCollection service, IConfiguration configuration1) { service.AddRateLimiter(option => { option.RejectionStatusCode = 429; option.OnRejected = async (context, ct) => { context.HttpContext.Response.ContentType = "application/json"; await context.HttpContext.Response.WriteAsJsonAsync(new ResponseBase() { Code = 3003, Data = null, Message = "API调用已达上限!" }, ct); }; option.AddPolicy("DynamicPerUser", context => { // 从前面中间件塞进来的 user 对象 var dto = context.Items["rateLimit"] as RateLimiterDto; string partitionKey; int limit; if (dto is null) { return RateLimitPartition.GetConcurrencyLimiter("unauthorized", _ => new ConcurrencyLimiterOptions { PermitLimit = 0, // 不允许任何请求 QueueProcessingOrder = QueueProcessingOrder.OldestFirst, QueueLimit = 0 }); } else { partitionKey = dto.UserId.ToString(); limit = dto.RateLimit; } return RateLimitPartition.GetFixedWindowLimiter( partitionKey, _ => new FixedWindowRateLimiterOptions { PermitLimit = limit, Window = TimeSpan.FromMinutes(1), QueueLimit = 0, QueueProcessingOrder = QueueProcessingOrder.OldestFirst }); }); }); return service; } } }