ql_apimanager_backend/Apimanager_backend/Config/ServiceCollectionExtensions.cs

186 lines
8.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<IUserService, UserService>();
services.AddScoped<IAuthService, AuthService>();
services.AddScoped<IAdminService, AdminService>();
services.AddScoped<IApiService, ApiService>();
services.AddScoped<IPackageService, PackageService>();
services.AddScoped<IOrderService, OrderService>();
services.AddScoped<IApiPackageItemService, ApiPackageItemService>();
services.AddScoped<IUserPackageService, UserPackageService>();
services.AddScoped<ISystemConfigService, SystemConfigService>();
services.AddScoped<IPaymentConfigService, PaymentConfigService>();
services.AddScoped<IPayService, PayService>();
services.AddSingleton<ITokenService, TokenService>();
services.AddSingleton<IRefreshTokenService, RefreshTokenService>();
services.AddSingleton<IEmailService, EmailService>();
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<JwtBearerChallengeContext, Task>(JwtTokenErrorEventFunc),
OnForbidden = new Func<ForbiddenContext, Task>(JwtPermissionEventFunc)
};
});
//redis配置
services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(configuration["Redis:ConnectionString"]));
return services;
}
/// <summary>
/// token无效事件处理函数
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async static Task JwtTokenErrorEventFunc(JwtBearerChallengeContext context)
{
context.Response.ContentType = "application/json";
var res = new ResponseBase<object?>(
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<object?>(
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<PluginLoaderService>();
var pluginLoaderService = services.BuildServiceProvider()
.GetRequiredService<PluginLoaderService>();
pluginLoaderService.LoadPlugins(services);
services.AddScoped<BillableApiDispatcher>();
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<object?>()
{
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;
}
}
}