Merge branch 'dev' of https://gitea.nxsir.cn/nanxun/ql_apimanager_backend into dev
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
using Apimanager_backend.Models;
|
||||
using System.Reflection;
|
||||
using System;
|
||||
using Apimanager_backend.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Apimanager_backend.Exceptions;
|
||||
using Apimanager_backend.Dtos;
|
||||
using Public;
|
||||
using Apimanager_backend.Services;
|
||||
|
||||
namespace Apimanager_backend.Tools
|
||||
{
|
||||
public class BillableApiDispatcher
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ApiContext _db;
|
||||
private PluginLoaderService _pluginLoaderService;
|
||||
|
||||
public BillableApiDispatcher(IServiceProvider sp, ApiContext db,PluginLoaderService pluginLoaderService)
|
||||
{
|
||||
_serviceProvider = sp;
|
||||
_db = db;
|
||||
_pluginLoaderService = pluginLoaderService;
|
||||
}
|
||||
|
||||
public async Task<object> DispatchAsync(string webPath,int apiId,string code, ApiCallContext context)
|
||||
{
|
||||
//_pluginLoaderService.LoadPlugins(new ServiceCollection());
|
||||
// 1. 安全验证
|
||||
string dllPath = webPath + "\\ApiHandler\\" + code + ".dll";
|
||||
if (!System.IO.File.Exists(dllPath))
|
||||
throw new BaseException(3002, "接口实现未找到");
|
||||
|
||||
// 2. 加载程序集
|
||||
var assembly = Assembly.LoadFrom(dllPath); // 或使用 AssemblyLoadContext.Default.LoadFromAssemblyPath
|
||||
|
||||
// 3. 查找实现类
|
||||
var type = assembly.GetTypes()
|
||||
.FirstOrDefault(t =>
|
||||
typeof(IBillableApiHandler).IsAssignableFrom(t) &&
|
||||
!t.IsInterface &&
|
||||
!t.IsAbstract &&
|
||||
t.Name.Equals(code, StringComparison.OrdinalIgnoreCase));
|
||||
if (type == null)
|
||||
throw new BaseException(3002,"接口实现未找到");
|
||||
|
||||
List<UserPackage> userPackages = context.HttpContext.Items["userPackages"] as List<UserPackage>;
|
||||
List<UserPackage> userPackageList = null;
|
||||
|
||||
if (userPackages == null || !(userPackages is IEnumerable<UserPackage>))
|
||||
{
|
||||
throw new BaseException(3004, "未购买该API套餐或权限不足");
|
||||
}
|
||||
|
||||
userPackageList = ((IEnumerable<UserPackage>)userPackages).ToList();
|
||||
|
||||
userPackageList = userPackageList.Where(x => x.ExpiryDate > DateTime.Now).ToList();
|
||||
|
||||
if (userPackageList.Count == 0)
|
||||
{
|
||||
throw new BaseException(3004, "未购买该API套餐或权限不足");
|
||||
}
|
||||
|
||||
|
||||
var maxCountUserPackage = userPackageList.MaxBy(x => x.RemainingCalls);
|
||||
|
||||
if (maxCountUserPackage.RemainingCalls <= 0)
|
||||
{
|
||||
throw new BaseException(3004, "套餐可用额度不足");
|
||||
}
|
||||
|
||||
var uPackage = await _db.UserPackages.SingleOrDefaultAsync(x => x.Id == maxCountUserPackage.Id);
|
||||
if (uPackage == null)
|
||||
{
|
||||
throw new BaseException(3004, "未购买该API套餐或权限不足");
|
||||
}
|
||||
|
||||
uPackage.RemainingCalls -= 1;
|
||||
|
||||
_db.UserPackages.Update(uPackage);
|
||||
|
||||
var handler = (IBillableApiHandler)Activator.CreateInstance(type)!;
|
||||
|
||||
// 执行接口
|
||||
var result = await handler.ExecuteAsync(context);
|
||||
|
||||
// 记录调用日志
|
||||
_db.CallLogs.Add(new ApiCallLog
|
||||
{
|
||||
ApiId = apiId,
|
||||
UserId = context.UserId,
|
||||
CallTime = DateTime.UtcNow
|
||||
});
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Apimanager_backend.Dtos;
|
||||
using Newtonsoft.Json;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Apimanager_backend.Tools
|
||||
{
|
||||
public static class EpayHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建签名
|
||||
/// </summary>
|
||||
public static string CreateSign(Dictionary<string, string> parameters, string key)
|
||||
{
|
||||
var sorted = parameters
|
||||
.Where(kv => !string.IsNullOrEmpty(kv.Value) && kv.Key != "sign" && kv.Key != "sign_type")
|
||||
.OrderBy(kv => kv.Key)
|
||||
.ToList();
|
||||
|
||||
string query = string.Join("&", sorted.Select(kv => $"{kv.Key}={kv.Value}"));
|
||||
string toSign = query + key;
|
||||
|
||||
using (var md5 = MD5.Create())
|
||||
{
|
||||
byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(toSign));
|
||||
return BitConverter.ToString(hash).Replace("-", "").ToLower();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 发起API支付(返回 json)
|
||||
/// </summary>
|
||||
public static async Task<EpayResponse?> ApiPayAsync(Dictionary<string, string> parameters, string key,string baseUrl)
|
||||
{
|
||||
parameters["sign_type"] = "MD5";
|
||||
parameters["sign"] = CreateSign(parameters, key);
|
||||
|
||||
using var client = new HttpClient();
|
||||
var content = new FormUrlEncodedContent(parameters);
|
||||
var response = await client.PostAsync($"{baseUrl}/mapi.php", content);
|
||||
return JsonConvert.DeserializeObject<EpayResponse>(await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验签名(通常用于异步通知/页面跳转)
|
||||
/// </summary>
|
||||
public static bool VerifySign(Dictionary<string, string> parameters, string key)
|
||||
{
|
||||
if (!parameters.TryGetValue("sign", out string originalSign)) return false;
|
||||
string newSign = CreateSign(parameters, key);
|
||||
return originalSign.Equals(newSign, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Apimanager_backend.Tools
|
||||
{
|
||||
public static class OrderNumberGenerator
|
||||
{
|
||||
public static string Generate(int userId = 0, string prefix = "ORD")
|
||||
{
|
||||
var datePart = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff"); // 17位
|
||||
var userPart = (userId % 10000).ToString("D4"); // 后4位用户ID
|
||||
var randPart = Random.Shared.Next(1000, 9999).ToString(); // 4位随机数
|
||||
|
||||
return $"{prefix}{datePart}{userPart}{randPart}"; // 最终:ORD + 时间 + 用户 + 随机数
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace Apimanager_backend.Tools
|
||||
{
|
||||
public static class UserInfoHelper
|
||||
{
|
||||
public static string GetClientIp(HttpContext context)
|
||||
{
|
||||
var ip = context.Connection.RemoteIpAddress?.ToString();
|
||||
|
||||
// 支持代理(如 Nginx)时使用 X-Forwarded-For
|
||||
if (context.Request.Headers.ContainsKey("X-Forwarded-For"))
|
||||
{
|
||||
ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
||||
}
|
||||
|
||||
return ip ?? "unknown";
|
||||
}
|
||||
public static string GetDeviceType(HttpContext context)
|
||||
{
|
||||
var userAgent = context.Request.Headers["User-Agent"].ToString().ToLower();
|
||||
|
||||
if (userAgent.Contains("mobile") || userAgent.Contains("android") || userAgent.Contains("iphone"))
|
||||
return "mobile";
|
||||
|
||||
return "pc";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user