package ufsdk import ( "crypto/hmac" "crypto/sha1" "encoding/base64" "fmt" "io" "net/http" "net/url" "sort" "strings" ) //Auth 构造签名的工具,使用本 SDK 你不需要关心 Auth 这一整个模块,以及它暴露出来的签名算法。 //如果你希望自己封装 API 可以使用这里面的暴露出来的接口来填充 http authorization。 type Auth struct { publicKey string privateKey string } //NewAuth 构造一个新的签名工具,传入你的公钥匙和私钥。 func NewAuth(publicKey, privateKey string) Auth { return Auth{ publicKey: publicKey, privateKey: privateKey, } } //Authorization 构造一个主要用于上传文件的签名,返回 HMAC-Sh1 的签名字符串,可以直接填充到 HTTP authorization header 里面。 //key 是传到 ufile 所使用的文件名,bucekt 是文件上传后存放的 bucket。 //method 就是你当前这个 HTTP 请求的 Method。 //header 就是你当前这个 HTTP 的 header。 func (A Auth) Authorization(method, bucket, key string, header http.Header) string { var sigData string method = strings.ToUpper(method) md5 := header.Get("Content-MD5") contentType := header.Get("Content-Type") date := header.Get("Date") sigData = method + "\n" + md5 + "\n" + contentType + "\n" + date + "\n" sigData += A.CanonicalizedUcloudHeaders(header) resource := "/" + bucket + "/" + key sigData += resource signature := A.signature(sigData) return "UCloud " + A.publicKey + ":" + signature } //AuthorizationPrivateURL 构造私有空间文件下载链接的签名,其中 expires 是当前的时间加上一个过期的时间,再转为字符串。格式是 unix time second. //其他的参数含义和 Authoriazation 函数一样。 //有时我们需要把签名后的 URL 直接拿来用,header 参数可以直接构造一个空的 http.Header{} 传入即可。 func (A Auth) AuthorizationPrivateURL(method, bucket, key, expires string, header http.Header) (string, string) { var sigData string method = strings.ToUpper(method) md5 := header.Get("Content-MD5") contentType := header.Get("Content-Type") sigData = method + "\n" + md5 + "\n" + contentType + "\n" + expires + "\n" resource := "/" + bucket + "/" + key sigData += resource signature := A.signature(sigData) return signature, A.publicKey } //AuthorizationPolicy 构造支持回调策略的签名,policy 是经过 base64 编码后的 json string。 //本签名函数就是多了一个 policy 字段,其他的参数和 Authoriazation 一样。 func (A Auth) AuthorizationPolicy(method, bucket, key, policy string, header http.Header) string { var sigData string method = strings.ToUpper(method) md5 := header.Get("Content-MD5") contentType := header.Get("Content-Type") date := header.Get("Date") sigData = method + "\n" + md5 + "\n" + contentType + "\n" + date + "\n" resource := "/" + bucket + "/" + key sigData += resource sigData += policy signature := A.signature(sigData) return "UCloud " + A.publicKey + ":" + signature + ":" + policy } func (A Auth) signature(data string) string { mac := hmac.New(sha1.New, []byte(A.privateKey)) mac.Write([]byte(data)) return base64.StdEncoding.EncodeToString(mac.Sum(nil)) } //AuthorizationBucketMgr 生成用于管理 bucket 的签名。 func (A Auth) AuthorizationBucketMgr(query url.Values) string { query.Add("PublicKey", A.publicKey) var signstring string var keys []string for k := range query { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { signstring += k + query.Get(k) //Get first value } signstring += A.privateKey h := sha1.New() io.WriteString(h, signstring) query.Add("Signature", fmt.Sprintf("%x", h.Sum(nil))) return query.Encode() } //CanonicalizedUcloudHeaders 用于将自定义请求报头规范化为string //ucloudHeader 支持自定义请求头 func (A Auth) CanonicalizedUcloudHeaders(ucloudHeader http.Header) string { keys := make([]string, 0) headers := make(map[string]string, 0) for k := range ucloudHeader { newkey := strings.ToLower(k) if strings.HasPrefix(newkey, "x-ufile-") || strings.HasPrefix(newkey, "x-ucloud-") { headers[newkey] = strings.TrimSpace(ucloudHeader[k][0]) keys = append(keys, newkey) } } sort.Strings(keys) s := "" for _, k := range keys { v := headers[k] s += k + ":" + v + "\n" } return s }