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 { /// /// 腾讯云COS服务实现 /// public class CosService : ICosService { private readonly TencentCosConfig _config; private readonly CosXml _cosXml; private readonly CosXmlConfig _cosXmlConfig; /// /// 构造函数 /// /// COS配置 public CosService(IOptions 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); } /// /// 生成签名URL /// /// 请求参数 /// 签名URL和过期时间 public async Task> 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(response); } catch (COSXML.CosException.CosClientException clientEx) { return new BaseResponse( ResponseCode.Error, $"生成签名URL失败(客户端错误):{clientEx.Message}"); } catch (COSXML.CosException.CosServerException serverEx) { return new BaseResponse( ResponseCode.Error, $"生成签名URL失败(服务器错误):{serverEx.GetInfo()}"); } catch (Exception ex) { return new BaseResponse( ResponseCode.Error, $"生成签名URL失败:{ex.Message}"); } } /// /// 生成临时密钥 /// /// 请求参数 /// 临时密钥信息 public async Task> 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 values = new Dictionary(); 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 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 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(tempKeyEntity); } catch (Exception ex) { return new BaseResponse( ResponseCode.Error, $"生成临时密钥失败:{ex.Message}"); } } } }