Initial commit

This commit is contained in:
fuenmao
2026-10-29 11:52:09 +08:00
commit 269cbf987d
248 changed files with 9099 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
using System.Globalization;
using System.Text.Json;
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Exceptions;
using Aliyun.Acs.Core.Http;
using Aliyun.Acs.Core.Profile;
using Aliyun.OSS;
using Microsoft.Extensions.Options;
namespace OssZipUploaderService
{
public class OssClientFactory
{
private readonly OssOptions _options;
public OssClientFactory(IOptions<OssOptions> options)
{
_options = options.Value;
}
// 每次上传前创建客户端,不复用上一次上传的临时凭据。
public OssClient CreateClient()
{
var accessKeyId = OssTJiaUploaderService.CryptoHelper.Decrypt(_options.AccessKeyId);
var accessKeySecret = OssTJiaUploaderService.CryptoHelper.Decrypt(_options.AccessKeySecret);
if (string.IsNullOrWhiteSpace(_options.RoleArn))
{
return new OssClient(_options.Endpoint, accessKeyId, accessKeySecret);
}
var profile = DefaultProfile.GetProfile(_options.StsRegionId, accessKeyId, accessKeySecret);
var stsClient = new DefaultAcsClient(profile);
CommonResponse response;
try
{
response = stsClient.GetCommonResponse(BuildAssumeRoleRequest());
}
catch (ClientException ex)
{
// 不将原始响应和凭据写入日志或钉钉消息。
throw new InvalidOperationException(
$"STS 扮演角色失败,错误码:{ex.ErrorCode},RequestId:{ex.RequestId}。" +
"请检查 RAM 用户的 sts:AssumeRole 权限、角色信任策略及 STS 配置。");
}
return CreateClientFromResponse(response.Data);
}
private CommonRequest BuildAssumeRoleRequest()
{
var request = new CommonRequest
{
Domain = _options.StsEndpoint,
Version = "2015-04-01",
Action = "AssumeRole",
Protocol = ProtocolType.HTTPS,
Method = MethodType.POST,
TimeoutInMilliSeconds = 30000
};
request.AddQueryParameters("RoleArn", _options.RoleArn);
request.AddQueryParameters("RoleSessionName", _options.RoleSessionName);
request.AddQueryParameters("DurationSeconds", _options.StsDurationSeconds.ToString(CultureInfo.InvariantCulture));
return request;
}
private OssClient CreateClientFromResponse(string responseData)
{
try
{
using var document = JsonDocument.Parse(responseData);
var credentials = document.RootElement.GetProperty("Credentials");
var accessKeyId = credentials.GetProperty("AccessKeyId").GetString();
var accessKeySecret = credentials.GetProperty("AccessKeySecret").GetString();
var securityToken = credentials.GetProperty("SecurityToken").GetString();
var expiration = credentials.GetProperty("Expiration").GetString();
if (string.IsNullOrWhiteSpace(accessKeyId) ||
string.IsNullOrWhiteSpace(accessKeySecret) ||
string.IsNullOrWhiteSpace(securityToken) ||
!DateTimeOffset.TryParse(expiration, CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal, out var expiresAt))
{
throw new InvalidOperationException("STS 返回的临时凭据不完整或过期时间无效。");
}
if (expiresAt <= DateTimeOffset.UtcNow.AddMinutes(1))
{
throw new InvalidOperationException("STS 临时凭据已过期或即将过期,请检查服务器时间。");
}
return new OssClient(_options.Endpoint, accessKeyId, accessKeySecret, securityToken);
}
catch (Exception ex) when (ex is JsonException || ex is KeyNotFoundException || ex is InvalidOperationException)
{
// JSON 解析异常可能包含响应片段,因此只返回固定错误信息。
throw new InvalidOperationException("STS 返回的临时凭据无效、已过期或即将过期,请检查 STS 响应和服务器时间。");
}
}
}
}