Files
finance_tjia/OssClientFactory.cs
2026-10-29 11:52:09 +08:00

102 lines
4.3 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 响应和服务器时间。");
}
}
}
}