366 lines
14 KiB
Markdown
366 lines
14 KiB
Markdown
# 腾讯云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
|
||
{
|
||
/// <summary>
|
||
/// 获取临时访问凭证
|
||
/// </summary>
|
||
public class CodeCosGenerateTemporaryKeyEntity
|
||
{
|
||
/// <summary>
|
||
/// 临时访问凭证
|
||
/// </summary>
|
||
public Credentials Credentials { get; set; }
|
||
/// <summary>
|
||
/// 临时访问凭证有效的时间,返回 Unix 时间戳,精确到秒
|
||
/// </summary>
|
||
public string Expiration { get; set; }
|
||
/// <summary>
|
||
/// 临时访问凭证有效的时间,以 iso8601 格式的 UTC 时间表示 注意:此字段可能返回 null,表示取不到有效值。
|
||
/// </summary>
|
||
public long ExpiredTime { get; set; }
|
||
|
||
/// <summary>
|
||
/// 开始时间
|
||
/// </summary>
|
||
public long StartTime { get; set; }
|
||
/// <summary>
|
||
/// 唯一请求 ID,由服务端生成,每次请求都会返回(若请求因其他原因未能抵达服务端,则该次请求不会获得 RequestId)。定位问题时需要提供该次请求的 RequestId。
|
||
/// </summary>
|
||
public string RequestId { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 临时访问凭证
|
||
/// </summary>
|
||
public class Credentials
|
||
{
|
||
/// <summary>
|
||
/// Token
|
||
/// </summary>
|
||
public string Token { get; set; }
|
||
/// <summary>
|
||
/// SecretId
|
||
/// </summary>
|
||
public string TmpSecretId { get; set; }
|
||
/// <summary>
|
||
/// SecretKey
|
||
/// </summary>
|
||
public string TmpSecretKey { get; set; }
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
public interface ICodeCosService : ISingletonDependency //:ITransientDependency: IScopedDependency
|
||
{
|
||
/// <summary>
|
||
/// 返回签名地址
|
||
/// </summary>
|
||
/// <param name="cosGenerateSign"></param>
|
||
/// <returns>sign签名值,过期时间</returns>
|
||
(string sign, int expiredSeconds) GenerateSignURL(CosGenerateSign cosGenerateSign);
|
||
/// <summary>
|
||
/// 生成临时密钥
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
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
|
||
{
|
||
/// <summary>
|
||
/// 腾讯云
|
||
/// </summary>
|
||
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();
|
||
}
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <param name="cosGenerateSign"></param>
|
||
/// <returns></returns>
|
||
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<string, object> values = new Dictionary<string, object>();
|
||
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<string, object> credential = STSClient.genCredential(values); //返回值说明见README.md
|
||
var json = JsonConvert.SerializeObject(credential);
|
||
var person = JsonConvert.DeserializeObject<CodeCosGenerateTemporaryKeyEntity>(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;
|
||
|
||
/// <summary>
|
||
/// 腾讯云COS服务
|
||
/// </summary>
|
||
public class CosService : ApplicationService
|
||
{
|
||
private readonly ICodeCosService _codeCosService;
|
||
private readonly TencentConfig _tencentConfig;
|
||
|
||
public CosService(ICodeCosService codeCosService, TencentConfig tencentConfig)
|
||
{
|
||
_codeCosService = codeCosService;
|
||
_tencentConfig = tencentConfig;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取签名
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public string GetCosSign()
|
||
{
|
||
var (sign, ex) = _codeCosService.GenerateSignURL(new CosGenerateSign());
|
||
return sign;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取临时签名
|
||
/// </summary>
|
||
/// <param name="fileName">文件名</param>
|
||
/// <param name="modelName">模型名称</param>
|
||
/// <returns></returns>
|
||
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<CodeCosGenerateTemporaryKeyEntity, GenerateTemporaryModel>() ?? 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;
|
||
|
||
/// <summary>
|
||
/// 腾讯云COS控制器
|
||
/// </summary>
|
||
[ControllerDescriptor(DisplayName = "腾讯云COS")]
|
||
public class CosController : AdminControllerBase<CosService>
|
||
{
|
||
public CosController(CosService defaultService)
|
||
: base(defaultService)
|
||
{
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取COS签名
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
[ActionDescriptor(DisplayName = "获取COS签名")]
|
||
public string GetCosSign()
|
||
{
|
||
return this._defaultService.GetCosSign();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取临时密钥
|
||
/// </summary>
|
||
/// <param name="fileName">文件名</param>
|
||
/// <param name="modelName">模型名称</param>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
[ActionDescriptor(DisplayName = "获取COS临时密钥")]
|
||
public GenerateTemporaryModel GetGenerateTemporaryKey(string fileName = "", string modelName = "")
|
||
{
|
||
return this._defaultService.GetGenerateTemporaryKey(fileName, modelName);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
``` |