MdpInboundAuthService.cs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. using Admin.NET.Core.Service;
  2. using Admin.NET.Plugin.AiDOP.Entity.DataPlatform;
  3. using SqlSugar;
  4. namespace Admin.NET.Plugin.AiDOP.DataPlatform.Inbound;
  5. /// <summary>grant 授权 + IP 白名单 + 限流。行数上限由接收服务按 grant/entity 取 min。</summary>
  6. public sealed class MdpInboundAuthService : ITransient
  7. {
  8. private readonly ISqlSugarClient _db;
  9. private readonly SysCacheService _cache;
  10. public MdpInboundAuthService(ISqlSugarClient db, SysCacheService cache)
  11. {
  12. _db = db;
  13. _cache = cache;
  14. }
  15. /// <summary>返回 null = 通过;否则 (httpStatus, message)。</summary>
  16. public async Task<(int Status, string Message)?> CheckAsync(
  17. string accessKey, long tenantId, string entityCode, string clientIp, CancellationToken ct)
  18. {
  19. var code = (entityCode ?? string.Empty).Trim().ToUpperInvariant();
  20. var entity = await _db.Queryable<MdpEntity>()
  21. .Where(e => e.InboundEnabled == 1)
  22. .Where("UPPER(entity_code) = @code", new SugarParameter("@code", code))
  23. .FirstAsync(ct);
  24. if (entity == null)
  25. return (403, "entity not authorized");
  26. var grant = await _db.Queryable<MdpInboundGrant>()
  27. .Where(g => g.AccessKey == accessKey && g.Status == 1)
  28. .Where("UPPER(entity_code) = @code", new SugarParameter("@code", code))
  29. .FirstAsync(ct);
  30. if (grant == null)
  31. return (403, "entity not authorized");
  32. if (grant.TenantId != tenantId)
  33. return (403, "entity not authorized");
  34. if (!string.IsNullOrWhiteSpace(grant.IpAllowlist))
  35. {
  36. var allowed = grant.IpAllowlist
  37. .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
  38. var ip = (clientIp ?? string.Empty).Trim();
  39. if (ip.Length == 0 || !allowed.Contains(ip, StringComparer.OrdinalIgnoreCase))
  40. return (403, "ip not allowed");
  41. }
  42. var minute = DateTime.Now.ToString("yyyyMMddHHmm");
  43. var rateKey = $"AIDOP_INBOUND_RATE:{accessKey}:{code}:{minute}";
  44. var current = _cache.Get<int>(rateKey);
  45. var next = current + 1;
  46. _cache.Set(rateKey, next, TimeSpan.FromMinutes(1));
  47. if (next > grant.RateLimitPerMin)
  48. return (429, "rate limit exceeded");
  49. return null;
  50. }
  51. public async Task<MdpInboundGrant> GetGrantAsync(string accessKey, string entityCode, CancellationToken ct)
  52. {
  53. var code = (entityCode ?? string.Empty).Trim().ToUpperInvariant();
  54. return await _db.Queryable<MdpInboundGrant>()
  55. .Where(g => g.AccessKey == accessKey && g.Status == 1)
  56. .Where("UPPER(entity_code) = @code", new SugarParameter("@code", code))
  57. .FirstAsync(ct);
  58. }
  59. }