为何使用私有空间
主要是公司内部系统的业务(质量管理系统),需要上传一些内部资料。 我不是很确实是否是保密信息,但是感觉上是不应该能够公开访问。 这不像是网站静态资源,例如网站图片,或者 js,css 等,上传就是为了公开能访问。
所以决定尝试一下七牛云存储的私有空间。(当然,阿里云也有类似的 OSS 存储服务。)
增加一个 bucket 空间
旧有的空间是开放空间,需要新建一个私有空间。
但是新增一个域名就麻烦了。。。
- 配置 CDN 域名
- 配置 HTTPS 证书
现在 七牛云 HTTPS 证书 只能配置3个月的,3个月后还需要手动重新配置。(去年还是可以设置一年的,今年就变成了 3 个月)
空间命名
因为目前公司内部的项目,又细分为不同子公司,不同的项目。为了省事,就使用同一个 CDN 域名,毕竟 3 个月手动换一次证书不是开玩笑的。
最好是区分好目录:
<子公司名缩写>/<项目名缩写>/<功能名缩写>/文件名
私有空间的原理
参考,七牛官方文档:
https://developer.qiniu.com/kodo/1656/download-private
下载链接需要附加参数 e 和 token。链接格式:
http://<domain>/<key>?e=<deadline>&token=<downloadToken>
- e 表示 URL 的过期时间,采用Unix时间戳,单位为秒。超时的访问将返回 401 错误。
- 参数 token 表示下载凭证。估计是对 e 的加密后的信息。下载凭证是对资源访问的授权,不带下载凭证或下载凭证不合法都会导致 401 错误,表示验证失败。
注意:token 参数需要放到 URL 的最后,其后面的参数将被忽略。
下载凭证的生成原理
参考:
https://developer.qiniu.com/kodo/1202/download-token
- 原始下载链接
- 下载链接加上 e 参数,即时间戳
- 对带时间戳的 URL 做 SHA1 计算,然后取 Base64 编码
- 拼接成 token,附加在 URL 最后。token 分为两部分,用冒号分隔。冒号前面是加密用的 key (官方 SDK 中默认使用的是 access key),冒号后是加密生成的串的 base64 编码。
一个真实文件的链接格式:
https://cdn.sunzhongwei.com/game/red-alert/test/image.jpg?e=1726101702&token=xxxxx:op7zkku4pLI-oG1KG6jf6hB9VGM=
这个文件链接,是通过手动上传文件到私有空间,然后在后台点击这个文件的菜单,选择“复制签名链接”获取到的。 默认的有效时间是 300 秒,即 5 分钟。
golang 相关接口
官方 Go SDK 的文档,真是一言难尽噶,看不懂:
https://developer.qiniu.com/kodo/1238/go#6
import (
"context"
"time"
"github.com/qiniu/go-sdk/v7/storagev2/credentials"
"github.com/qiniu/go-sdk/v7/storagev2/downloader"
)
accessKey := "your access key"
secretKey := "your secret key"
mac := credentials.NewCredentials(accessKey, secretKey)
domain := "download.domain.com"
urlsProvider := downloader.SignURLsProvider(downloader.NewStaticDomainBasedURLsProvider([]string{domain}), downloader.NewCredentialsSigner(mac), &downloader.SignOptions{
TTL: 1 * time.Hour, // 有效期
})
需要结合 github 上的代码来看。
https://github.com/qiniu/go-sdk/blob/master/storagev2/downloader/signers.go
很奇怪这里用的都是 storagev2 的接口,跟 storage 的区别是什么呢?从 github 代码来看,storage 中也会使用 storagev2 中的 downloader 相关的接口。 我看 upload token 也是用这个 storagev2 接口生成的。
需要本地用实际代码测试一下。例如,手动在七牛后台上传,然后用 sdk 生成下载链接,测试是否能够正确下载,过期后是否会禁止下载。
可用代码
还是得靠 AI。。。
看了一下午 sdk 的源码,最后被 AI 一秒钟解决了。。。。
https://github.com/qiniu/go-sdk/blob/master/storage/bucket.go#L1275
对应的 sdk 代码:
使用里面的 MakePrivateURLv2 即可。
// MakePrivateURL 用来生成私有空间资源下载链接,注意该方法并不会对 key 进行 escape
func MakePrivateURL(mac *auth.Credentials, domain, key string, deadline int64) (privateURL string) {
publicURL := MakePublicURL(domain, key)
urlToSign := publicURL
if strings.Contains(publicURL, "?") {
urlToSign = fmt.Sprintf("%s&e=%d", urlToSign, deadline)
} else {
urlToSign = fmt.Sprintf("%s?e=%d", urlToSign, deadline)
}
token := mac.Sign([]byte(urlToSign))
privateURL = fmt.Sprintf("%s&token=%s", urlToSign, token)
return
}
// MakePrivateURLv2 用来生成私有空间资源下载链接,并且该方法确保 key 将会被 escape
func MakePrivateURLv2(mac *auth.Credentials, domain, key string, deadline int64) (privateURL string) {
return MakePrivateURLv2WithQuery(mac, domain, key, nil, deadline)
}
// MakePublicURL 用来生成公开空间资源下载链接,注意该方法并不会对 key 进行 escape
func MakePublicURL(domain, key string) (finalUrl string) {
domain = strings.TrimRight(domain, "/")
srcUrl := fmt.Sprintf("%s/%s", domain, key)
srcUri, _ := url.Parse(srcUrl)
finalUrl = srcUri.String()
return
}
例如生成一个有效期为 1 个小时的下载链接:
mac := qbox.NewMac(qiniu_access_key, qiniu_secret_key)
url := storage.MakePrivateURLv2(
mac, qiniu_url_prefix_private, key,
time.Now().Add(time.Hour*1).Unix())
手动测试
- 手动上传一个文件到私有空间。记录这个文件的 key, 即,文件路径,tx/qms/test/GWjt0QqWIAAiszg.jpg
- 在 golang 项目的配置文件中,新增一个私有空间的相关配置。但是我从七牛后台看,多个空间,可以使用相同的 AK/SK (Access Key / Secret Key)。
error: download token auth failed
但是我生成的 token,冒号前的部分为空。如:
image.jpg?e=1726107479&token=:PdHKk8Gg-yTofbUwDwlpLb6xbL8=
且没有域名。原来是单元测试代码,没有加载 .env 里的七牛云参数配置。
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式