214 lines
8.3 KiB
C#
214 lines
8.3 KiB
C#
using COSXML;
|
||
using COSXML.Auth;
|
||
using COSXML.Model.Object;
|
||
using COSSTS;
|
||
using LiveForum.Code.Base;
|
||
using LiveForum.IService.Others;
|
||
using LiveForum.Model.Dto.Others;
|
||
using Microsoft.Extensions.Options;
|
||
using Newtonsoft.Json;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Threading.Tasks;
|
||
using COSXML.Model.Tag;
|
||
|
||
namespace LiveForum.Service.Others
|
||
{
|
||
/// <summary>
|
||
/// 腾讯云COS服务实现
|
||
/// </summary>
|
||
public class CosService : ICosService
|
||
{
|
||
private readonly TencentCosConfig _config;
|
||
private readonly CosXml _cosXml;
|
||
private readonly CosXmlConfig _cosXmlConfig;
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
/// <param name="config">COS配置</param>
|
||
public CosService(IOptions<TencentCosConfig> config)
|
||
{
|
||
_config = config.Value;
|
||
|
||
// 初始化COS配置
|
||
_cosXmlConfig = new CosXmlConfig.Builder()
|
||
.SetRegion(_config.Region)
|
||
.Build();
|
||
|
||
// 创建凭证提供者
|
||
var qCloudCredentialProvider = new DefaultQCloudCredentialProvider(
|
||
_config.SecretId,
|
||
_config.SecretKey,
|
||
_config.DurationSecond);
|
||
|
||
// 初始化COS客户端
|
||
_cosXml = new CosXmlServer(_cosXmlConfig, qCloudCredentialProvider);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成签名URL
|
||
/// </summary>
|
||
/// <param name="request">请求参数</param>
|
||
/// <returns>签名URL和过期时间</returns>
|
||
public async Task<BaseResponse<CosGenerateSignRespDto>> GenerateSignURL(CosGenerateSignReq request)
|
||
{
|
||
try
|
||
{
|
||
var preSignatureStruct = new PreSignatureStruct
|
||
{
|
||
appid = _config.AppId,
|
||
region = _config.Region,
|
||
bucket = $"{_config.BucketName}-{_config.AppId}",
|
||
key = request.Key,
|
||
httpMethod = request.HttpMethod,
|
||
isHttps = request.IsHttps,
|
||
signDurationSecond = _config.DurationSecond,
|
||
headers = null,
|
||
queryParameters = null
|
||
};
|
||
|
||
// 生成预签名URL
|
||
string signUrl = _cosXml.GenerateSignURL(preSignatureStruct);
|
||
|
||
var response = new CosGenerateSignRespDto
|
||
{
|
||
SignUrl = signUrl,
|
||
ExpiredSeconds = (int)_config.DurationSecond
|
||
};
|
||
|
||
return new BaseResponse<CosGenerateSignRespDto>(response);
|
||
}
|
||
catch (COSXML.CosException.CosClientException clientEx)
|
||
{
|
||
return new BaseResponse<CosGenerateSignRespDto>(
|
||
ResponseCode.Error,
|
||
$"生成签名URL失败(客户端错误):{clientEx.Message}");
|
||
}
|
||
catch (COSXML.CosException.CosServerException serverEx)
|
||
{
|
||
return new BaseResponse<CosGenerateSignRespDto>(
|
||
ResponseCode.Error,
|
||
$"生成签名URL失败(服务器错误):{serverEx.GetInfo()}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return new BaseResponse<CosGenerateSignRespDto>(
|
||
ResponseCode.Error,
|
||
$"生成签名URL失败:{ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成临时密钥
|
||
/// </summary>
|
||
/// <param name="request">请求参数</param>
|
||
/// <returns>临时密钥信息</returns>
|
||
public async Task<BaseResponse<CosGenerateTemporaryKeyRespDto>> GenerateTemporaryKey(CosGenerateTemporaryKeyReq request)
|
||
{
|
||
try
|
||
{
|
||
// 验证和设置参数
|
||
string bucket = $"{_config.BucketName}-{_config.AppId}";
|
||
string region = _config.Region;
|
||
string prefixes = request.Prefixes ?? _config.Prefixes;
|
||
|
||
// 允许的路径前缀
|
||
string allowPrefix = "*";
|
||
|
||
// 密钥的权限列表
|
||
string[] allowActions = new string[]
|
||
{
|
||
"name/cos:PutObject",
|
||
"name/cos:PostObject",
|
||
"name/cos:InitiateMultipartUpload",
|
||
"name/cos:ListMultipartUploads",
|
||
"name/cos:ListParts",
|
||
"name/cos:UploadPart",
|
||
"name/cos:CompleteMultipartUpload"
|
||
};
|
||
|
||
// 设置参数
|
||
Dictionary<string, object> values = new Dictionary<string, object>();
|
||
values.Add("bucket", bucket);
|
||
values.Add("region", region);
|
||
values.Add("allowPrefix", allowPrefix);
|
||
values.Add("allowPrefixes", new string[] { string.IsNullOrEmpty(prefixes) ? "file/*" : $"{prefixes}/*" });
|
||
values.Add("allowActions", allowActions);
|
||
values.Add("durationSeconds", _config.DurationSecond);
|
||
values.Add("secretId", _config.SecretId);
|
||
values.Add("secretKey", _config.SecretKey);
|
||
|
||
// 生成临时凭证
|
||
Dictionary<string, object> credential = STSClient.genCredential(values);
|
||
|
||
// 手动映射字段(因为STS返回的字段名可能与DTO不完全匹配)
|
||
var tempKeyEntity = new CosGenerateTemporaryKeyRespDto
|
||
{
|
||
Bucket = bucket,
|
||
Region = region,
|
||
Prefixes = prefixes
|
||
};
|
||
|
||
// 提取凭证信息
|
||
if (credential.TryGetValue("credentials", out var credsObj) && credsObj is Dictionary<string, object> credsDict)
|
||
{
|
||
tempKeyEntity.Credentials = new CredentialsDto
|
||
{
|
||
Token = credsDict.TryGetValue("token", out var token) ? token?.ToString() ?? string.Empty : string.Empty,
|
||
TmpSecretId = credsDict.TryGetValue("tmpSecretId", out var tmpSecretId) ? tmpSecretId?.ToString() ?? string.Empty : string.Empty,
|
||
TmpSecretKey = credsDict.TryGetValue("tmpSecretKey", out var tmpSecretKey) ? tmpSecretKey?.ToString() ?? string.Empty : string.Empty
|
||
};
|
||
}
|
||
|
||
// 提取时间信息
|
||
if (credential.TryGetValue("expiration", out var expiration))
|
||
{
|
||
tempKeyEntity.Expiration = expiration?.ToString() ?? string.Empty;
|
||
}
|
||
|
||
if (credential.TryGetValue("expiredTime", out var expiredTime) && expiredTime != null)
|
||
{
|
||
if (long.TryParse(expiredTime.ToString(), out long expiredTimeLong))
|
||
{
|
||
tempKeyEntity.ExpiredTime = expiredTimeLong;
|
||
}
|
||
}
|
||
|
||
if (credential.TryGetValue("startTime", out var startTime) && startTime != null)
|
||
{
|
||
if (long.TryParse(startTime.ToString(), out long startTimeLong))
|
||
{
|
||
tempKeyEntity.StartTime = startTimeLong;
|
||
}
|
||
}
|
||
|
||
// 生成文件路径
|
||
string modelName = string.IsNullOrEmpty(request.ModelName) ? "images" : request.ModelName;
|
||
string fileName = request.FileName;
|
||
if (!string.IsNullOrEmpty(fileName))
|
||
{
|
||
var ext = System.IO.Path.GetExtension(fileName);
|
||
if (!string.IsNullOrEmpty(ext))
|
||
{
|
||
// 使用 UTC 时间生成时间戳文件名
|
||
fileName = $"{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}{ext}";
|
||
}
|
||
}
|
||
|
||
tempKeyEntity.FilePath = $"{prefixes}/{modelName}/{DateTime.Now:yyyyMMdd}/{fileName}";
|
||
tempKeyEntity.DomainName = _config.DomainUrl;
|
||
|
||
return new BaseResponse<CosGenerateTemporaryKeyRespDto>(tempKeyEntity);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return new BaseResponse<CosGenerateTemporaryKeyRespDto>(
|
||
ResponseCode.Error,
|
||
$"生成临时密钥失败:{ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|