# 腾讯云cos 1.由于服务的限制,现需要在项目中集成腾讯cos服务。需要实现的功能:上传文件。返回签名。生成临时密钥。 ## 上传文件需要实现的功能。 1.需要实现接口:IFileUploadService,需要实现的原因时,后面可以通过依赖注入去直接在系统全局中把原来的上传的本地,变成上传到cos上。 后端\项目\LiveForum\LiveForum.WebApi\Controllers\FileUploadController.cs 这个是上传到本地的控制器,等腾讯云实现了,会修改依赖注入的IFileUploadService对象。 ## 返回签名、生成临时密钥 这个需要新增cos服务接口,新增cos控制器,新增对应的接口。 1.由于服务器的带宽太小,所以有备选方案,前端在请求签名后,去生成临时密钥,直接去上传到cos,不经过服务器了。 参考下面代码: ```C# using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MiaoYu.Core.Cos.Models { /// /// 获取临时访问凭证 /// public class CodeCosGenerateTemporaryKeyEntity { /// /// 临时访问凭证 /// public Credentials Credentials { get; set; } /// /// 临时访问凭证有效的时间,返回 Unix 时间戳,精确到秒 /// public string Expiration { get; set; } /// /// 临时访问凭证有效的时间,以 iso8601 格式的 UTC 时间表示 注意:此字段可能返回 null,表示取不到有效值。 /// public long ExpiredTime { get; set; } /// /// 开始时间 /// public long StartTime { get; set; } /// /// 唯一请求 ID,由服务端生成,每次请求都会返回(若请求因其他原因未能抵达服务端,则该次请求不会获得 RequestId)。定位问题时需要提供该次请求的 RequestId。 /// public string RequestId { get; set; } } /// /// 临时访问凭证 /// public class Credentials { /// /// Token /// public string Token { get; set; } /// /// SecretId /// public string TmpSecretId { get; set; } /// /// SecretKey /// public string TmpSecretKey { get; set; } } } /// /// /// public interface ICodeCosService : ISingletonDependency //:ITransientDependency: IScopedDependency { /// /// 返回签名地址 /// /// /// sign签名值,过期时间 (string sign, int expiredSeconds) GenerateSignURL(CosGenerateSign cosGenerateSign); /// /// 生成临时密钥 /// /// CodeCosGenerateTemporaryKeyEntity GenerateTemporaryKey(CosGenerateSign cosGenerateSign); } using COSXML.Model.Object; using COSXML.Model.Tag; using COSXML; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using COSXML.Auth; using MiaoYu.Core.Cos.Configs; using NPOI.SS.Formula.Functions; using COSSTS; using Newtonsoft.Json; using System.Collections; using TencentCloud.Tci.V20190318.Models; namespace MiaoYu.Core.Cos.Services.Impl { /// /// 腾讯云 /// public class TencentCodeCosService : ICodeCosService//ISingletonDependency //: IScopedDependency//: ITransientDependency { //public TencentCodeCosService() { } private CosXml cosXml; private TencentCosConfig tencentCosConfig; private TencentConfig tencentConfig; CosXmlConfig config = null; public TencentCodeCosService(TencentConfig tencentConfig) { this.tencentConfig = tencentConfig; this.tencentCosConfig = tencentConfig.CosConfig; if (config == null) { config = new CosXmlConfig.Builder() //.SetRegion("COS_REGION") // 设置默认的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224 .Build(); } string secretId = tencentCosConfig.SecretId; // 云 API 密钥 SecretId, 获取 API 密钥请参照 https://console.cloud.tencent.com/cam/capi string secretKey = tencentCosConfig.SecretKey; // 云 API 密钥 SecretKey, 获取 API 密钥请参照 https://console.cloud.tencent.com/cam/capi long durationSecond = tencentCosConfig.DurationSecond; //每次请求签名有效时长,单位为秒 QCloudCredentialProvider qCloudCredentialProvider = new DefaultQCloudCredentialProvider(secretId, secretKey, durationSecond); this.cosXml = new CosXmlServer(config, qCloudCredentialProvider); } public (string sign, int expiredSeconds) GenerateSignURL(CosGenerateSign cosGenerateSign) { try { PreSignatureStruct preSignatureStruct = new PreSignatureStruct(); // APPID 获取参考 https://console.cloud.tencent.com/developer preSignatureStruct.appid = tencentCosConfig.AppId; // 存储桶所在地域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224 preSignatureStruct.region = tencentCosConfig.Region; // 存储桶名称,此处填入格式必须为 bucketname-APPID, 其中 APPID 获取参考 https://console.cloud.tencent.com/developer preSignatureStruct.bucket = tencentCosConfig.Bucket + "-" + tencentCosConfig.AppId;// "examplebucket-1250000000"; preSignatureStruct.key = "exampleobject"; //对象键 preSignatureStruct.httpMethod = "PUT"; //HTTP 请求方法 preSignatureStruct.isHttps = true; //生成 HTTPS 请求 URL preSignatureStruct.signDurationSecond = tencentCosConfig.DurationSecond; //请求签名时间为 600s preSignatureStruct.headers = null;//签名中需要校验的 header preSignatureStruct.queryParameters = null; //签名中需要校验的 URL 中请求参数 //上传预签名 URL (使用永久密钥方式计算的签名 URL) string requestSignURL = cosXml.GenerateSignURL(preSignatureStruct); return new(requestSignURL, (int)tencentCosConfig.DurationSecond); } catch (COSXML.CosException.CosClientException clientEx) { //请求失败 Console.WriteLine("CosClientException: " + clientEx); } catch (COSXML.CosException.CosServerException serverEx) { //请求失败 Console.WriteLine("CosServerException: " + serverEx.GetInfo()); } throw new NotImplementedException(); } /// /// /// /// /// public CodeCosGenerateTemporaryKeyEntity GenerateTemporaryKey(CosGenerateSign cosGenerateSign) { #region 验证区域 if (string.IsNullOrEmpty(cosGenerateSign.Bucket)) { cosGenerateSign.Bucket = tencentCosConfig.Bucket; } if (string.IsNullOrEmpty(cosGenerateSign.AppId)) { cosGenerateSign.AppId = tencentCosConfig.AppId; } if (string.IsNullOrEmpty(cosGenerateSign.Region)) { cosGenerateSign.Region = tencentCosConfig.Region; } #endregion string bucket = cosGenerateSign.Bucket + "-" + cosGenerateSign.AppId; // 您的 bucket string region = cosGenerateSign.Region;// bucket 所在区域 // 改成允许的路径前缀,根据自己网站的用户判断允许上传的路径,例子:a.jpg 或者 a/* 或者 * (通配符*存在重大安全风险, 谨慎评估使用) string allowPrefix = "*"; /* * 密钥的权限列表。必须在这里指定本次临时密钥所需要的权限。权限列表请参见 https://cloud.tencent.com/document/product/436/31923 * 规则为 {project}:{interfaceName} * project : 产品缩写 cos相关授权为值为cos,数据万象(数据处理)相关授权值为ci * 授权所有接口用*表示,例如 cos:*,ci:* */ 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); // 也可以通过 allowPrefixes 指定路径前缀的集合 values.Add("allowPrefixes", new string[] { string.IsNullOrEmpty(cosGenerateSign.Prefixes)?"miaoyu/*":cosGenerateSign.Prefixes, }); values.Add("allowActions", allowActions); values.Add("durationSeconds", 600);//指定临时证书的有效期, 参考 https://cloud.tencent.com/document/product/1312/48195 values.Add("secretId", tencentCosConfig.SecretId); values.Add("secretKey", tencentCosConfig.SecretKey); Dictionary credential = STSClient.genCredential(values); //返回值说明见README.md var json = JsonConvert.SerializeObject(credential); var person = JsonConvert.DeserializeObject(json); return person; } } } using MiaoYu.Api.Admin.ApplicationServices.Systems.Cos.Dtos; using MiaoYu.Core.ApplicationServices; using MiaoYu.Core.Cos.Configs; using MiaoYu.Core.Cos.Models; using MiaoYu.Core.Cos.Services; namespace MiaoYu.Api.Admin.ApplicationServices.Systems.Cos; /// /// 腾讯云COS服务 /// public class CosService : ApplicationService { private readonly ICodeCosService _codeCosService; private readonly TencentConfig _tencentConfig; public CosService(ICodeCosService codeCosService, TencentConfig tencentConfig) { _codeCosService = codeCosService; _tencentConfig = tencentConfig; } /// /// 获取签名 /// /// public string GetCosSign() { var (sign, ex) = _codeCosService.GenerateSignURL(new CosGenerateSign()); return sign; } /// /// 获取临时签名 /// /// 文件名 /// 模型名称 /// public GenerateTemporaryModel GetGenerateTemporaryKey(string fileName = "", string modelName = "") { var cosConfig = _tencentConfig.CosConfig; var t = new CosGenerateSign() { Prefixes = cosConfig.Prefixes ?? "file", Bucket = cosConfig?.Bucket, Region = cosConfig?.Region, AppId = cosConfig?.AppId, SecretId = cosConfig?.SecretId, SecretKey = cosConfig?.SecretKey, DurationSecond = cosConfig?.DurationSecond ?? 300 }; if (string.IsNullOrEmpty(modelName)) { modelName = "images"; } var tempFile = fileName; if (!string.IsNullOrEmpty(tempFile)) { var ext = Path.GetExtension(tempFile); if (!string.IsNullOrEmpty(ext)) { // 使用 UTC 时间生成时间戳文件名 tempFile = $"{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}{ext}"; } } var model = _codeCosService.GenerateTemporaryKey(t); // 复制对象属性,本项目中集成了Mapster框架,使用Adapt转换即可 var generateTemporaryModel = model.CopyObject() ?? new GenerateTemporaryModel(); generateTemporaryModel.Bucket = t.Bucket + "-" + t.AppId; generateTemporaryModel.Region = t.Region; generateTemporaryModel.Prefixes = t.Prefixes; // 修复日期格式:yyyMMdd -> yyyyMMdd generateTemporaryModel.FilePath = $"{t.Prefixes}/{modelName}/{DateTime.Now.ToString("yyyyMMdd")}/{tempFile}"; generateTemporaryModel.DomainName = cosConfig.DomainName; return generateTemporaryModel; } } using MiaoYu.Api.Admin.ApplicationServices.Systems.Cos; using MiaoYu.Api.Admin.ApplicationServices.Systems.Cos.Dtos; namespace MiaoYu.Api.Admin.Controllers.Systems; /// /// 腾讯云COS控制器 /// [ControllerDescriptor(DisplayName = "腾讯云COS")] public class CosController : AdminControllerBase { public CosController(CosService defaultService) : base(defaultService) { } /// /// 获取COS签名 /// /// [HttpGet] [ActionDescriptor(DisplayName = "获取COS签名")] public string GetCosSign() { return this._defaultService.GetCosSign(); } /// /// 获取临时密钥 /// /// 文件名 /// 模型名称 /// [HttpGet] [ActionDescriptor(DisplayName = "获取COS临时密钥")] public GenerateTemporaryModel GetGenerateTemporaryKey(string fileName = "", string modelName = "") { return this._defaultService.GetGenerateTemporaryKey(fileName, modelName); } } ```