视频点播提供了 Referer 防盗链和 IP 黑白名单的功能对访客进行过滤。但是在某些情况下,Referer 和 IP 可以被伪造,容易造成站点资源被恶意盗用。如果您对于站点内容的安全性有很高的要求,可以采用 URL 鉴权的方式。本文为您介绍 URL 鉴权的流程、签名计算的原理、逻辑关系和多种语言的 Demo 示例等内容。
客户端在发送请求至服务端时,按照您设定的签名规则计算签名,并在请求中包含这个签名。服务端收到请求后,需要校验签名。只有在校验通过的情况下,才会响应客户端请求。您可以通过示例代码了解实现签名规则的逻辑,也可以了解在视频点播中配置访问 URL 的鉴权逻辑。
客户端在计算签名时,需要的参数如下表所示。
参数 | 说明 |
---|---|
key | 表示在视频点播控制台配置的密钥。可以使用主密钥或者备用密钥。详见为点播加速域名开启并配置 A 类型的 URL 鉴权。 |
uri | 表示请求的文件路径。路径以斜杠 |
timestamp | 表示 URL 过期时间,格式是十进制的 Unix 时间戳。示例: |
rand | 表示一个随机字符串。长度为 1-100 位。可以包含字母和数字。示例: |
uid | 表示用户 ID,暂时未使用。设置成 0 即可。 |
参数 | 示例值 |
---|---|
key | abc123def456 |
uri | /img/volcano.png |
rand | 2e1ca42a1bb248408fc9cf435e5af744 |
uid | 0 |
timestamp | 1644406401 |
scheme://host/uri?auth_key=timestamp-rand-uid-md5(uri-timestamp-rand-uid-key)(&...)
基于该请求格式,使用以下公式计算签名:md5(/img/volcano.png-1644406401-2e1ca42a1bb248408fc9cf435e5af744-0-abc123def456)
MD5 值在鉴权时会转化成小写进行比较。
https://www.example.com/img/volcano.png?auth_key=1644406401-2e1ca42a1bb248408fc9cf435e5af744-0-54959c1ec3448bf8e992554476248fab
为方便您快速进行签名计算,点播提供了多种语言的 Demo 示例。
package main import ( "crypto/md5" "encoding/hex" "fmt" "math/rand" "regexp" "strconv" "time" ) func splitUrl(url string) []string { reg := regexp.MustCompile("^(http://|https://)?([^/?]+)(/[^?]*)?(\\?.*)?$") return reg.FindStringSubmatch(url) } func getMd5(text string) string { hashByte := md5.Sum([]byte(text)) return hex.EncodeToString(hashByte[:]) } func getRandomString(length int) string { b := make([]byte, length) rand.Read(b) return fmt.Sprintf("%x", b)[:length] } func GenTypeAUrl(url string, key string, signName string, uid string, ts int64) string { params := splitUrl(url) scheme, host, path, args := params[1], params[2], params[3], params[4] randstr := getRandomString(10) text := fmt.Sprintf("%s-%d-%s-%s-%s", path, ts, randstr, uid, key) hash := getMd5(text) authArg := fmt.Sprintf("%s=%d-%s-%s-%s", signName, ts, randstr, uid, hash) if args == "" { return fmt.Sprintf("%s%s%s?%s", scheme, host, path, authArg) } else { return fmt.Sprintf("%s%s%s%s&%s", scheme, host, path, args, authArg) } } func GenTypeBUrl(url string, key string, ts int64) string { params := splitUrl(url) scheme, host, path, args := params[1], params[2], params[3], params[4] tsStr := time.Unix(ts, 0).Format("200601021504") text := fmt.Sprintf("%s%s%s", key, tsStr, path) hash := getMd5(text) return fmt.Sprintf("%s%s/%s/%s%s%s", scheme, host, tsStr, hash, path, args) } func GenTypeCUrl(url string, key string, ts int64) string { params := splitUrl(url) scheme, host, path, args := params[1], params[2], params[3], params[4] tsStr := strconv.FormatInt(ts, 16) text := fmt.Sprintf("%s%s%s", key, path, tsStr) hash := getMd5(text) return fmt.Sprintf("%s%s/%s/%s%s%s", scheme, host, hash, tsStr, path, args) } func GenTypeDUrl(url, key, signName, timeName string, ts int64, base int) string { params := splitUrl(url) scheme, host, path, args := params[1], params[2], params[3], params[4] tsStr := strconv.FormatInt(ts, base) text := fmt.Sprintf("%s%s%s", key, path, tsStr) hash := getMd5(text) authArg := fmt.Sprintf("%s=%s&%s=%s", signName, hash, timeName, tsStr) if args == "" { return fmt.Sprintf("%s%s%s?%s", scheme, host, path, authArg) } else { return fmt.Sprintf("%s%s%s%s&%s", scheme, host, path, args, authArg) } } // GenTypeEUrl Genrate signed url by custom rule(eg.:key+domain+uri+timestamp) func GenTypeEUrl(url, key, signName, tsName string, ts int64, base int) string { params := splitUrl(url) scheme, domain, uri, args := params[1], params[2], params[3], params[4] tsStr := strconv.FormatInt(ts, base) text := fmt.Sprintf("%s%s%s%s", key, domain, uri, tsStr) hash := getMd5(text) authArg := fmt.Sprintf("%s=%s&%s=%s", signName, hash, tsName, tsStr) if args == "" { return fmt.Sprintf("%s%s%s?%s", scheme, domain, uri, authArg) } else { return fmt.Sprintf("%s%s%s%s&%s", scheme, domain, uri, args, authArg) } } func init() { rand.Seed(time.Now().UnixNano()) } func main() { var url = "http://www.test.com/a.txt?a=b&c=d" var primaryKey = "primary123456" var signName = "auth_key" var timeName = "t" var uid = "0" var ts = time.Now().Unix() + 3600 //默认一小时过期 typeAUrl := GenTypeAUrl(url, primaryKey, signName, uid, ts) typeBUrl := GenTypeBUrl(url, primaryKey, ts) typeCUrl := GenTypeCUrl(url, primaryKey, ts) typeDUrl := GenTypeDUrl(url, primaryKey, signName, timeName, ts, 10) typeEUrl := GenTypeEUrl(url, primaryKey, signName, timeName, ts, 10) fmt.Println("OriginUrl: ", url) fmt.Println("TypeA: ", typeAUrl) fmt.Println("TypeB: ", typeBUrl) fmt.Println("TypeC: ", typeCUrl) fmt.Println("TypeD: ", typeDUrl) fmt.Println("TypeE: ", typeEUrl) }