Initial commit
This commit is contained in:
@@ -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 响应和服务器时间。");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user