基于时候戳防盗链的功用实在每家的CDN都是支撑的。主假如经由过程运用商定的加密字符串来对具有接见有效期的资本链接举行一些加密盘算的到一个sign
值,然后接见外链内里带上这个sign
和停止时候戳去接见CDN的节点,CDN的节点会用一样的算法来盘算接见链接是不是正当,假如不正当则返回403 Forbidden
,不然返回所要接见的资本。
算法申明
基于时候戳的防盗链是经由过程对时候有关的字符串举行署名,将时候,署名经由过程肯定的体式格局通报给CDN服务器作为剖断根据,CDN边沿节点根据商定的算法推断来访的URL是不是有接见权限。
假如经由过程,实行下一步;假如不经由过程,相应 HTTP 状况码 403。假如同时设置了Referer体式格局防盗链,UserAgent防盗链,时候戳防盗链,那末假如有个中一项没有经由过程,那末即相应403。
署名参数
参数 | 形貌 |
---|---|
T | URL逾期的时候,把Unix以秒为单元的时候戳,用16进制的小写字母情势示意。比方 2016-06-30 22:57:42 +0800 CST 对应的时候戳是 1467298662 ,示意为16进制就是 57753366 。 |
key | 和CDN商定好的加密字符串 |
path | 接见资本外链的PATH部份,比方假如接见的外链是http://if-pbl.qiniudn.com/golang.png?v=1 那末个中PATH部份就是/golang.png |
署名算法
待署名的原始字符串
s=key+path+T
署名体式格局
sign=md5(s).to_lower()
,个中to_lower()
示意天生的md5字符串用小写字母示意
署名参数通报体式格局
比方原始接见外链是:http://if-pbl.qiniudn.com/golang.png?v=1
终究构成的接见外链是:http://if-pbl.qiniudn.com/golang.png?v=1&sign=xxxx&t=xxxx
个中xxxx
对应各自的值。
算法参考完成
package com.qiniulab.cdn;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Hex;
public class CdnAntiLeech {
/**
* 天生资本基于CDN时候戳防盗链的接见外链
*
* @param 资本原始外链
* @param 效果资本的有效期,单元秒
* @throws MalformedURLException
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
*/
public static String getAntiLeechAccessUrlBasedOnTimestamp(String url, String encryptKey, int durationInSeconds)
throws MalformedURLException, UnsupportedEncodingException, NoSuchAlgorithmException {
URL urlObj = new URL(url);
String path = urlObj.getPath();
long timestampNow = System.currentTimeMillis() / 1000 + durationInSeconds;
String expireHex = Long.toHexString(timestampNow);
String toSignStr = String.format("%s%s%s", encryptKey, path, expireHex);
String signedStr = md5ToLower(toSignStr);
String signedUrl = null;
if (urlObj.getQuery() != null) {
signedUrl = String.format("%s&sign=%s&t=%s", url, signedStr, expireHex);
} else {
signedUrl = String.format("%s?sign=%s&t=%s", url, signedStr, expireHex);
}
return signedUrl;
}
private static String md5ToLower(String src) throws UnsupportedEncodingException, NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(src.getBytes("utf-8"));
byte[] md5Bytes = digest.digest();
return Hex.encodeHexString(md5Bytes);
}
}
运用体式格局
// cdn 设置的基于时候戳防盗链的加密字符串,cdn 设置完成后会获得
String encryptKey = "";
// 待加密链接
String fileKey = "xxxx.pdf";
String encodedFileKey;
try {
// 考虑到文件名称会有中文,所以需要做urlencode
encodedFileKey = URLEncoder.encode(fileKey, "utf-8");
String urlToSign = String.format("http://img.abc.com/%s", encodedFileKey);
// 有效期
int duration = 3600;
String signedUrl = CdnAntiLeech.getAntiLeechAccessUrlBasedOnTimestamp(urlToSign, encryptKey, duration);
System.out.println(signedUrl);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}