⭐️ 我把它分为了两个步骤一个是获取临时密钥,一个是获取预签名的URL

1️⃣ 获取临时密钥

需要通过 sts包来创建 Client,注意这里不是 go-sdk包,而是 sts-sdk包,填写固定的 SecretIDSecretKey,

	c := sts.NewClient(
		// 通过环境变量获取密钥, os.Getenv 方法表示获取环境变量
		os.Getenv("SECRETID"), //这里是填写固定的
		os.Getenv("SECRETKEY"),//这里是填写固定的
		nil,
	)

填写创建密钥的 Options

opt := &sts.CredentialOptions{
		DurationSeconds: int64(time.Hour.Seconds()), //持续时间
		Region:          "ap-hongkong",	//区域
		Policy: &sts.CredentialPolicy{ //Policy
			Statement: []sts.CredentialPolicyStatement{
				{
					Action: []string{ //权限
						"name/cos:PostObject",
						"name/cos:PutObject",
						"name/cos:GetObject",
					},
					Effect: "allow", //有 allow (允许)和 deny (显式拒绝)两种情况
					Resource: []string{  //授权操作的具体数据,可以是任意资源、指定路径前缀的资源、指定绝对路径的资源或它们的组合
						//这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径,例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
						//存储桶的命名格式为 BucketName-APPID,此处填写的 bucket 必须为此格式
						"qcs::cos: ap-hongkong:uid/" + os.Getenv("APPID") + ":" + os.Getenv("BUCKET") + "/upload/video/*",
					},
				},
			},
		},
	}

随后通过 GetCredential获取临时密钥,查看`Credentials结构,它里面已经包含了获取的临时信息了,在对接cos时会用到

type Credentials struct {
	TmpSecretID  string `json:"TmpSecretId,omitempty"`
	TmpSecretKey string `json:"TmpSecretKey,omitempty"`
	SessionToken string `json:"Token,omitempty"`
}

下面时完整代码

import (
	"context"
	"github.com/tencentyun/cos-go-sdk-v5"
	sts "github.com/tencentyun/qcloud-cos-sts-sdk/go"
	"net/http"
	"net/url"
	"os"
	"time"
)

// CosToken 获取腾讯云cos临时密钥
func CosToken() (*sts.Credentials, error) {
	c := sts.NewClient(
		// 通过环境变量获取密钥, os.Getenv 方法表示获取环境变量
		os.Getenv("SECRETID"),
		os.Getenv("SECRETKEY"),
		nil,
	)
	// 策略概述 https://cloud.tencent.com/document/product/436/18023
	opt := &sts.CredentialOptions{
		DurationSeconds: int64(time.Hour.Seconds()),
		Region:          [这里需要填写区域名]如ap-chengdu,
		Policy: &sts.CredentialPolicy{
			Statement: []sts.CredentialPolicyStatement{
				{
					Action: []string{
						"name/cos:PostObject",
						"name/cos:PutObject",
						"name/cos:GetObject",
					},
					Effect: "allow",
					Resource: []string{
						//这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径,例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
						//存储桶的命名格式为 BucketName-APPID,此处填写的 bucket 必须为此格式
						"qcs::cos: ap-hongkong:uid/" + os.Getenv("APPID") + ":" + os.Getenv("BUCKET") + "/upload/video/*",
					},
				},
			},
		},
	}
	res, err := c.GetCredential(opt)
	if err != nil {
		return nil, err
	}
	return res.Credentials, nil
}

2️⃣ 生成预签名(对接 cos)

我这里配合了 gin的自定义验证器,接收一个 FileName

首先调用你获取临时密钥函数,来获取临时密钥

	token, err := utils.CosToken()
	if err != nil {
		logrus.Error("获取临时密钥失败", err.Error())
		return gin.H{
			"code": -1,
			"msg":  "获取临时密钥失败",
		}
	}

创建对接 cosclient,它接收一个 BaseUrl和一个 http.client,这里的 url是存储桶的访问地址

u, _ := url.Parse("https://存储桶名.cos.区域.myqcloud.com")
b := &cos.BaseURL{BucketURL: u}
c := cos.NewClient(b, &http.Client{})

这里获取文件后缀名后,通过 uuid+后缀名的方式来生成 key,这个 key,可以理解为对象上传后存储的位置

//获取文件后缀
	ext := filepath.Ext(service.FileName)
	// 对象键(Key)是对象在存储桶中的唯一标识。
	// 例如,在对象的访问域名 `examplebucket-1250000000.cos.COS_REGION.myqcloud.com/test/objectPut.go` 中,对象键为 test/objectPut.go
	//key := "upload/video/" + service.FileName
	key := "upload/video/" + utils.GenerateUUID() + ext

注意预签名 urlmethod,需要在临时 token中的 Action中允许

生成上传(put)预签名 url,通过,Option设置接收的 vaule和头文件,随后通过获取的后缀来判断文件传输的类型,在通过 Query.Add来添加 token

第一个参数指定上下文的 Background,第二个参数指定 urlmethod这里的 SeesionTokenSecretIDSecretKey是需要获取临时 token内的,然后就是超时时间,最后时 options

	opt := &cos.PresignedURLOptions{
		Query: &url.Values{},
		Header: &http.Header{
			//设置上传文件类型
			"Content-Type": []string{mime.TypeByExtension(ext)},
		},
	}

	//添加session
	opt.Query.Add("x-cos-security-token", token.SessionToken)
	//获取上传文件预签名Url
	putURL, err := c.Object.GetPresignedURL(context.Background(), http.MethodPut, key, token.TmpSecretID, token.TmpSecretKey, time.Hour, opt)
	if err != nil {
		logrus.Error("上传失败", err.Error())
		return gin.H{
			"code": -1,
			"msg":  "获取上传预签名失败",
		}
	}

Get预签名也是同理,只不过不需要添加文件类型

	opt2 := &cos.PresignedURLOptions{
		Query:  &url.Values{},
		Header: &http.Header{},
	}

	//添加session
	opt2.Query.Add("x-cos-security-token", token.SessionToken)
	//获取查看文件预签名Url
	getURL, errGet := c.Object.GetPresignedURL(context.Background(), http.MethodGet, key, token.TmpSecretID, token.TmpSecretKey, time.Hour, opt2)
	if errGet != nil {
		logrus.Error("获取失败", errGet.Error())
		return gin.H{
			"code": -1,
			"msg":  "获取下载预签名失败",
		}
	}

下面时完整代码


import (
	"GliGliVideo/utils"
	"context"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"github.com/tencentyun/cos-go-sdk-v5"
	"mime"
	"net/http"
	"net/url"
	"path/filepath"
	"time"
)

type VideoUploadSvc struct {
	FileName string `json:"file_name" form:"file_name"`
}

func (service *VideoUploadSvc) Post() gin.H {
	token, err := utils.CosToken()
	if err != nil {
		logrus.Error("获取临时密钥失败", err.Error())
		return gin.H{
			"code": -1,
			"msg":  "获取临时密钥失败",
		}
	}
	// 将 examplebucket-1250000000 和 COS_REGION 修改为真实的信息
	// 存储桶名称,由 bucketname-appid 组成,appid 必须填入,可以在 COS 控制台查看存储桶名称。https://console.cloud.tencent.com/cos5/bucket
	// COS_REGION 可以在控制台查看,https://console.cloud.tencent.com/cos5/bucket, 关于地域的详情见 https://cloud.tencent.com/document/product/436/6224
	u, _ := url.Parse("https://存储桶名.cos.区域.myqcloud.com")
	b := &cos.BaseURL{BucketURL: u}
	c := cos.NewClient(b, &http.Client{})

	//获取文件后缀
	ext := filepath.Ext(service.FileName)
	// 对象键(Key)是对象在存储桶中的唯一标识。
	// 例如,在对象的访问域名 `examplebucket-1250000000.cos.COS_REGION.myqcloud.com/test/objectPut.go` 中,对象键为 test/objectPut.go
	//key := "upload/video/" + service.FileName
	key := "upload/video/" + utils.GenerateUUID() + ext
	opt := &cos.PresignedURLOptions{
		Query: &url.Values{},
		Header: &http.Header{
			//设置上传文件类型
			"Content-Type": []string{mime.TypeByExtension(ext)},
		},
	}

	//添加session
	opt.Query.Add("x-cos-security-token", token.SessionToken)
	//获取上传文件预签名Url
	putURL, err := c.Object.GetPresignedURL(context.Background(), http.MethodPut, key, token.TmpSecretID, token.TmpSecretKey, time.Hour, opt)
	if err != nil {
		logrus.Error("上传失败", err.Error())
		return gin.H{
			"code": -1,
			"msg":  "获取上传预签名失败",
		}
	}
	opt2 := &cos.PresignedURLOptions{
		Query:  &url.Values{},
		Header: &http.Header{},
	}

	//添加session
	opt2.Query.Add("x-cos-security-token", token.SessionToken)
	//获取查看文件预签名Url
	getURL, errGet := c.Object.GetPresignedURL(context.Background(), http.MethodGet, key, token.TmpSecretID, token.TmpSecretKey, time.Hour, opt2)
	if errGet != nil {
		logrus.Error("获取失败", errGet.Error())
		return gin.H{
			"code": -1,
			"msg":  "获取下载预签名失败",
		}
	}

	return gin.H{
		"code": 200,
		"msg":  "success",
		"key":  key,
		"get":  getURL.String(),
		"put":  putURL.String(),
	}
}