186 lines
8.0 KiB
C#
186 lines
8.0 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|