diff --git a/AuthGate/SimApiAuthGate.cs b/AuthGate/SimApiAuthGate.cs
new file mode 100644
index 0000000..6b5e3ed
--- /dev/null
+++ b/AuthGate/SimApiAuthGate.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Net.Http.Json;
+using SimApi.Communications;
+using static SimApi.Helpers.SimApiError;
+
+namespace SimApi.AuthGate;
+
+public class SimApiAuthGate(SimApiAuthGateClient simapi)
+{
+ #region AuthGate公开接口
+
+ ///
+ /// 委托AuthCenter进行应用签名验证
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void VerifySign(string appId, string timestamp, string nonce, string sign)
+ {
+ var http = new HttpClient();
+ var url = $"{simapi.Server}/api/auth/sign/verify?appId={appId}×tamp={timestamp}&nonce={nonce}&sign={sign}";
+ var result = http.PostAsJsonAsync(url, new { }).Result;
+ var resp = result.Content.ReadFromJsonAsync().Result;
+ ErrorWhenNull(resp, 400, "签名验证失败");
+ ErrorWhenFalse(resp.Code == 200, 400, "签名验证失败");
+ }
+
+ ///
+ /// 根据关键字,搜索用户Profile,参数支持精准ID,用户手机号,用户邮箱,Profile名称模糊搜索
+ ///
+ ///
+ ///
+ ///
+ ///
+ public SimApiAuthGateDto.AppAndProfileItem[]? ProfileSearch(string keyword, int skip = 0, int take = 20)
+ {
+ return simapi.SignQuery("/api/auth/profile/search",
+ new { keyword, skip, take });
+ }
+
+ ///
+ /// 通过id,可以批量获取用户的基本信息
+ ///
+ ///
+ ///
+ public SimApiAuthGateDto.AppAndProfileItem[]? ProfileList(string[] ids)
+ {
+ return simapi.SignQuery("/api/auth/profile/list", new { ids });
+ }
+
+ #endregion
+
+ #region AuthGate内部应用专用 - 注意: 只有内部应用可以调用
+
+ ///
+ /// 获取是否为App的拥有者
+ ///
+ ///
+ ///
+ ///
+ public bool CheckIsAppOwner(string profileId, string applicationId)
+ {
+ return simapi.SignQuery("/api/auth/internal/apps/check-owner", new
+ {
+ ProfileId = profileId,
+ AppId = applicationId,
+ });
+ }
+
+ ///
+ /// 获取应用列表,根据用户profileId 和 提供的appIds
+ ///
+ ///
+ ///
+ ///
+ public SimApiAuthGateDto.AppAndProfileItem[]? GetAppList(string profileId, IEnumerable appIds)
+ {
+ return simapi.SignQuery("/api/auth/internal/apps/related", new
+ {
+ ProfileId = profileId,
+ AllowedAppIds = appIds,
+ });
+ }
+
+ #endregion
+
+ #region 系统登录
+
+ ///
+ /// 获取登录授权CODE
+ ///
+ ///
+ ///
+ ///
+ ///
+ public SimApiAuthGateDto.GetCodeResponse GetAuthCode(string? scene = null, Dictionary? data = null,
+ string? backUrl = null)
+ {
+ var code = simapi.SignQuery("/api/auth/confirm/code",
+ new { scene, data, backUrl });
+ return new SimApiAuthGateDto.GetCodeResponse()
+ {
+ Code = code!,
+ Server = simapi.Server,
+ FullUrl = $"{simapi.Server}/auth?code={code}"
+ };
+ }
+
+ ///
+ /// 使用code获取登录信息
+ ///
+ ///
+ ///
+ ///
+ public SimApiAuthGateDto.AuthInfoResponse GetAuthInfo(string code, string? scene = null)
+ {
+ var resp = simapi.SignQuery("/api/auth/confirm/get", new { code });
+ ErrorWhenNull(resp, 400232, "登录信息获取失败");
+ ErrorWhen(resp.Scene != scene, 403003, "登录场景不匹配");
+ return resp;
+ }
+
+ #endregion
+
+ #region 安全验证
+
+ ///
+ /// 获取安全验证代码
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public SimApiAuthGateDto.GetCodeResponse GetConfirmCode(string scene, string userId,
+ Dictionary? data = null,
+ string? backUrl = null)
+ {
+ var code = simapi.SignQuery("/api/auth/confirm/code",
+ new { scene, data, backUrl, profileId = userId });
+ return new SimApiAuthGateDto.GetCodeResponse()
+ {
+ Code = code!,
+ Server = simapi.Server,
+ FullUrl = $"{simapi.Server}/confirm?code={code}"
+ };
+ }
+
+ ///
+ /// 使用安全验证code 获取验证结果
+ ///
+ ///
+ ///
+ ///
+ ///
+ public SimApiAuthGateDto.ConfirmResponse Confirm(string code, string scene, string? userId = null)
+ {
+ var resp = simapi.SignQuery("/api/auth/confirm/get", new { code });
+ ErrorWhenNull(resp, 403001, "安全确认码无效");
+ ErrorWhen(resp.ProfileId != userId, 403002, "安全确认身份不匹配");
+ ErrorWhen(resp.Scene != scene, 403003, "安全确认场景不匹配");
+ return resp;
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/AuthGate/SimApiAuthGateClient.cs b/AuthGate/SimApiAuthGateClient.cs
new file mode 100644
index 0000000..c3776d5
--- /dev/null
+++ b/AuthGate/SimApiAuthGateClient.cs
@@ -0,0 +1,11 @@
+using SimApi.Configurations;
+using SimApi.Helpers;
+
+namespace SimApi.AuthGate;
+
+public class SimApiAuthGateClient(SimApiOptions apiOptions) : SimApiHttpClient
+{
+ public override string Server { get; init; } = apiOptions.SimApiAuthGateOptions.Server ?? string.Empty;
+ public override string AppId { get; init; } = apiOptions.SimApiAuthGateOptions.AppId ?? string.Empty;
+ public override string AppKey { get; init; } = apiOptions.SimApiAuthGateOptions.AppKey ?? string.Empty;
+}
\ No newline at end of file
diff --git a/AuthGate/SimApiAuthGateDto.cs b/AuthGate/SimApiAuthGateDto.cs
new file mode 100644
index 0000000..47b80e4
--- /dev/null
+++ b/AuthGate/SimApiAuthGateDto.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+
+namespace SimApi.AuthGate;
+
+public class SimApiAuthGateDto
+{
+ public class AppAndProfileItem
+ {
+ public string Id { get; set; } = "";
+ public string Name { get; set; } = "";
+ public string? Image { get; set; }
+ public string? Description { get; set; }
+ }
+
+ public class ConfirmResponse
+ {
+ public required string ApplicationId { get; set; }
+ public required string ProfileId { get; set; }
+ public string? Scene { get; set; }
+ public Dictionary? Data { get; set; }
+ }
+
+ public class AuthInfoResponse
+ {
+ public string? Scene { get; set; }
+ public Dictionary? Data { get; set; }
+ public required string ProfileId { get; set; }
+ public required string Name { get; set; }
+ public string? Image { get; set; }
+ public string? Description { get; set; }
+ }
+
+ public class GetCodeResponse
+ {
+ public required string Code { get; set; }
+ public required string Server { get; set; }
+ public required string FullUrl { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Middlewares/SimApiGateAuthMiddleware.cs b/AuthGate/SimApiAuthGateMiddleware.cs
similarity index 76%
rename from Middlewares/SimApiGateAuthMiddleware.cs
rename to AuthGate/SimApiAuthGateMiddleware.cs
index e3c3127..d6821a1 100644
--- a/Middlewares/SimApiGateAuthMiddleware.cs
+++ b/AuthGate/SimApiAuthGateMiddleware.cs
@@ -1,14 +1,13 @@
-using System;
-using System.Threading.Tasks;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using SimApi.Communications;
using SimApi.Configurations;
using SimApi.Helpers;
-namespace SimApi.Middlewares;
+namespace SimApi.AuthGate;
-public class SimApiGateAuthMiddleware(RequestDelegate next, ILogger logger)
+public class SimApiAuthGateMiddleware(RequestDelegate next, ILogger logger)
{
public Task Invoke(HttpContext httpContext, SimApiOptions simApiOptions)
{
@@ -17,7 +16,7 @@ public class SimApiGateAuthMiddleware(RequestDelegate next, ILogger {signStr}");
if (SimApiUtil.Md5(signStr) == sign && !string.IsNullOrEmpty(auth))
{
diff --git a/AuthGate/SimApiIam.cs b/AuthGate/SimApiIam.cs
new file mode 100644
index 0000000..033ec3e
--- /dev/null
+++ b/AuthGate/SimApiIam.cs
@@ -0,0 +1,45 @@
+using Microsoft.Extensions.Logging;
+using static SimApi.Helpers.SimApiError;
+
+namespace SimApi.AuthGate;
+
+public class SimApiIam(SimApiAuthGateClient simapi, ILogger logger)
+{
+ ///
+ /// 向Iam注册权限
+ ///
+ ///
+ public void RegisterPermissions(SimApiIamDto.PermissionItem[] permissions)
+ {
+ var log = $"检测到 {permissions.Length} 个权限接口,正在注册..: ";
+ foreach (var permission in permissions)
+ {
+ log += $"\n |- {permission.Identifier} => [{permission.Group}]{permission.Name} ({permission.Description})";
+ }
+
+ logger.LogInformation(log);
+ simapi.SignQuery("/api/iam/permission/register", new { permissions });
+ logger.LogInformation("权限注册完成");
+ }
+
+ ///
+ /// 获取拥有的权限标识数组
+ ///
+ ///
+ ///
+ public string[] GetPermissionOwned(string profileId)
+ {
+ return simapi.SignQuery("/api/iam/permission/owned", new { profileId }) ?? [];
+ }
+
+ ///
+ /// 检测profileId是否有这个权限
+ ///
+ ///
+ ///
+ public void CheckPermission(string profileId, string permission)
+ {
+ var ok = simapi.SignQuery("/api/iam/permission/check", new { profileId, permission });
+ ErrorWhen(!ok, 403, "没有该权限");
+ }
+}
\ No newline at end of file
diff --git a/AuthGate/SimApiIamDto.cs b/AuthGate/SimApiIamDto.cs
new file mode 100644
index 0000000..8a3683c
--- /dev/null
+++ b/AuthGate/SimApiIamDto.cs
@@ -0,0 +1,12 @@
+namespace SimApi.AuthGate;
+
+public class SimApiIamDto
+{
+ public class PermissionItem
+ {
+ public required string Identifier { get; init; }
+ public required string Name { get; init; }
+ public required string Group { get; init; }
+ public required string Description { get; init; }
+ }
+}
\ No newline at end of file
diff --git a/Configurations/SimApiAuthGateOptions.cs b/Configurations/SimApiAuthGateOptions.cs
new file mode 100644
index 0000000..c2563d2
--- /dev/null
+++ b/Configurations/SimApiAuthGateOptions.cs
@@ -0,0 +1,14 @@
+namespace SimApi.Configurations;
+
+public class SimApiAuthGateOptions
+{
+ public string? Server { get; set; }
+ public string? AppId { get; set; }
+ public string? AppKey { get; set; }
+
+ ///
+ /// 开启则使用内部网关透传的Middleware
+ /// 注意: 只有内部应用需要开启这个,也就是api通过内部网关代理后
+ ///
+ public bool UseMiddleware { get; set; }
+}
\ No newline at end of file
diff --git a/Configurations/SimApiGateAuthOptions.cs b/Configurations/SimApiGateAuthOptions.cs
deleted file mode 100644
index 85597ea..0000000
--- a/Configurations/SimApiGateAuthOptions.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace SimApi.Configurations;
-
-public class SimApiGateAuthOptions
-{
- public string? AppId { get; set; }
-
- public string? AppKey { get; set; }
-}
\ No newline at end of file
diff --git a/Configurations/SimApiOptions.cs b/Configurations/SimApiOptions.cs
index c2d5db3..4f10fa2 100644
--- a/Configurations/SimApiOptions.cs
+++ b/Configurations/SimApiOptions.cs
@@ -20,12 +20,7 @@ public class SimApiOptions
///
/// 启用SimApi网关授权, 基于上层网关透传的身份令牌验证
///
- public bool EnableSimApiGateAuth { get; set; }
-
- ///
- /// 是否使用CoceSdk
- ///
- public bool EnableCoceSdk { get; set; }
+ public bool EnableSimApiAuthGate { get; set; }
///
/// 开启S3兼容的存储系统。
@@ -109,7 +104,7 @@ public class SimApiOptions
public SimApiSynapseOptions SimApiSynapseOptions { get; set; } = new();
- public SimApiGateAuthOptions SimApiGateAuthOptions { get; set; } = new();
+ public SimApiAuthGateOptions SimApiAuthGateOptions { get; set; } = new();
public SimApiHttpClientOptions SimApiHttpClientOptions { get; set; } = new();
@@ -145,8 +140,8 @@ public class SimApiOptions
options?.Invoke(SimApiJobOptions);
}
- public void ConfigureSimApiGateAuth(Action? options = null)
+ public void ConfigureSimApiAuthGate(Action? options = null)
{
- options?.Invoke(SimApiGateAuthOptions);
+ options?.Invoke(SimApiAuthGateOptions);
}
}
\ No newline at end of file
diff --git a/Controllers/SimApiAuthController.cs b/Controllers/SimApiAuthController.cs
index 100bb03..9bb52e5 100644
--- a/Controllers/SimApiAuthController.cs
+++ b/Controllers/SimApiAuthController.cs
@@ -21,4 +21,5 @@ public class SimApiAuthController(SimApiAuth auth) : SimApiBaseController
auth.Logout(value!);
}
}
+
}
\ No newline at end of file
diff --git a/Helpers/SimApiHttpClient.cs b/Helpers/SimApiHttpClient.cs
index 7e98061..9aedc6b 100644
--- a/Helpers/SimApiHttpClient.cs
+++ b/Helpers/SimApiHttpClient.cs
@@ -12,15 +12,15 @@ namespace SimApi.Helpers;
public class SimApiHttpClient(SimApiOptions? apiOptions = null, ILogger? logger = null)
{
- public string Server { get; init; } = apiOptions?.SimApiHttpClientOptions.Server ?? string.Empty;
- public string AppId { get; init; } = apiOptions?.SimApiHttpClientOptions.AppId ?? string.Empty;
- public string AppKey { get; init; } = apiOptions?.SimApiHttpClientOptions.AppKey ?? string.Empty;
+ public virtual string Server { get; init; } = apiOptions?.SimApiHttpClientOptions.Server ?? string.Empty;
+ public virtual string AppId { get; init; } = apiOptions?.SimApiHttpClientOptions.AppId ?? string.Empty;
+ public virtual string AppKey { get; init; } = apiOptions?.SimApiHttpClientOptions.AppKey ?? string.Empty;
- public string SignName { get; init; } = "sign";
- public string TimestampName { get; init; } = "timestamp";
- public string NonceName { get; init; } = "nonce";
- public string? AppIdName { get; init; } = "appId";
- public string[] SignFields { get; init; } = [];
+ public virtual string SignName { get; init; } = "sign";
+ public virtual string TimestampName { get; init; } = "timestamp";
+ public virtual string NonceName { get; init; } = "nonce";
+ public virtual string? AppIdName { get; init; } = "appId";
+ public virtual string[] SignFields { get; init; } = [];
///
/// 发起签名请求
diff --git a/SimApiExtensions.cs b/SimApiExtensions.cs
index 9fe75d8..e83347a 100644
--- a/SimApiExtensions.cs
+++ b/SimApiExtensions.cs
@@ -16,6 +16,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using SimApi.Attributes;
+using SimApi.AuthGate;
using SimApi.Configurations;
using SimApi.Interfaces;
using SimApi.Logger;
@@ -328,6 +329,13 @@ public static class SimApiExtensions
});
}
+ if (simApiOptions.EnableSimApiAuthGate)
+ {
+ builder.AddSingleton();
+ builder.AddSingleton();
+ builder.AddSingleton();
+ }
+
builder.AddSingleton(simApiOptions);
return builder;
}
@@ -411,17 +419,20 @@ public static class SimApiExtensions
logger.LogInformation(msg);
}
- if (options.EnableSimApiGateAuth)
+ if (options.EnableSimApiAuthGate)
{
- logger.LogInformation("开始配置SimApiGateAuth...");
- if (string.IsNullOrEmpty(options.SimApiGateAuthOptions.AppId) ||
- string.IsNullOrEmpty(options.SimApiGateAuthOptions.AppKey))
+ logger.LogInformation("开始配置SimApiAuthGate...");
+ if (string.IsNullOrEmpty(options.SimApiAuthGateOptions.AppId) ||
+ string.IsNullOrEmpty(options.SimApiAuthGateOptions.AppKey))
{
- logger.LogCritical("必须配置Gate的AppId和AppKey才能启用SimApiGateAuth");
+ logger.LogCritical("必须配置AuthGate的AppId和AppKey才能启用SimApiAuthGate");
}
else
{
- builder.UseMiddleware();
+ if (options.SimApiAuthGateOptions.UseMiddleware)
+ {
+ builder.UseMiddleware();
+ }
}
}