先前写过阿里云oss签名直传,使用的是java。后来由于使用了golang重写,于是就有了使用golang实现的签名直传。golang版与java版一致,只不过换成了golang的oss sdk。
第一步 引用阿里云oss golang sdk
go get github.com/aliyun/aliyun-oss-go-sdk/oss
第二步 最好创建阿里云client以备用
client, err := oss.New(api.Conf.EndPoint, api.Conf.AccessKey, api.Conf.SecretKey)
参数有EndPoint AccessKey SecretKey
第三步 通过secret 获取签名
// ConfigStruct {"expiration":"2023-01-12T07:59:00.678Z","conditions":[["content-length-range",0,104857600],["starts-with","$key","12345"],{"key":"12345/23.txt"}]}
// 签名内容的json格式
type ConfigStruct struct {
Expiration string `json:"expiration"`
Conditions []any `json:"conditions"`
}
type CallbackParam struct {
CallbackUrl string `json:"callbackUrl"`
CallbackBody string `json:"callbackBody"`
CallbackBodyType string `json:"callbackBodyType"`
}
// getPolicyToken 获取预签名参数
func getPolicyToken(accessKey, accessSecret, hostWithBucket, pathPrefix, fullKey, callBackUrl, fileId string, expireTime int64) PolicyToken {
// 计算上传签名的有效时间
now := time.Now().Unix()
expire_end := now + expireTime
var tokenExpire = time.Unix(expire_end, 0).UTC().Format("2006-01-02T15:04:05Z")
//create post policy json 大至最终结构如下
// {"expiration":"2023-01-12T07:59:00.678Z","conditions":[["content-length-range",0,104857600],["starts-with","$key","12345"],{"key":"12345/23.txt"}]}
var config ConfigStruct
config.Expiration = tokenExpire
{
// starts-with key以什么开头,用于限制上传的key的开头字符串
var condition []string
condition = append(condition, "starts-with") // starts-with range exact
condition = append(condition, "$key") // key Expires Content-Encoding Content-Disposition Content-Type Cache-Control content-length-range success_action_redirect success_action_status x-oss-meta- x-oss-server-side-
condition = append(condition, pathPrefix)
config.Conditions = append(config.Conditions, condition)
}
{
// 长度限制 content-length-range 0-100m 用于限制上传的文件的大小
var condition []any
condition = append(condition, "content-length-range") // starts-with range exact
condition = append(condition, 0)
condition = append(condition, 104857600)
config.Conditions = append(config.Conditions, condition)
}
{
// key 限制 用于限制上传的key本身的值 与上边限制开头功能重复
var condition = map[string]string{}
condition["key"] = fullKey
config.Conditions = append(config.Conditions, condition)
}
//calucate signature Policy: struct->jsonStr->bytes->base64
// 结果的转换 Signature: struct->jsonStr->bytes->base64->sha1[with oss secret]->base64
result, err := json.Marshal(config)
debyte := base64.StdEncoding.EncodeToString(result)
h := hmac.New(func() hash.Hash { return sha1.New() }, []byte(accessSecret))
io.WriteString(h, debyte)
signedStr := base64.StdEncoding.EncodeToString(h.Sum(nil))
// 回调地址设置 Callback: json->bytes->base64
var callbackParam CallbackParam
callbackParam.CallbackUrl = callBackUrl
callbackParam.CallbackBody = "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}&id=" + fileId
callbackParam.CallbackBodyType = "application/x-www-form-urlencoded"
callback_str, err := json.Marshal(callbackParam)
if err != nil {
fmt.Println("callback json err:", err)
}
callbackBase64 := base64.StdEncoding.EncodeToString(callback_str)
// 计算完成 组合返回结果
var policyToken PolicyToken
policyToken.AccessKeyId = accessKey
policyToken.Host = hostWithBucket
policyToken.Expire = expire_end
policyToken.Signature = string(signedStr)
policyToken.Directory = pathPrefix
policyToken.Policy = string(debyte)
policyToken.Callback = string(callbackBase64)
return policyToken
}
第四步 在前端上传文件
以uniapp为例
var uploadTask = uni.uploadFile({
url: res.host, // 返回参数中带桶名的上传地址 如 https://bucketname.beijing.alioss.com
filePath: file.path, // 从相册中选择的地址,小程序应该是个文件临时地址
name: 'file', // from中文件名为file,一定要填file,不然阿里OSS不认
header: {},
formData: {
'key': res.key, // 返回签名参数中的key
'policy': res.policy, // 返回签名参数中的policy
'OSSAccessKeyId': res.accessId, // 返回参数中的的accesskey
'success_action_status': '200', //如果不设置success_action_status为200,文件上传成功后则返回204状态码。
'signature': res.signature, // 返回参数中的上传签名
"callback": res.callback // 返回参数中的回调参数
},
success: (uploadFileRes) => {
// 上传成功回调方法
})
}
});
注意
在上传时multiform里要把file放在最后把key放在最前