阿里云CDN签名-Java版本

由于官方之提供了php版本,故此提供java版本给大家使用


伸手党 福利


import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.UUID;
import java.util.logging.Logger;
 * 阿里云cdn 鉴权加密工具
 * <p>有效时间1800s指用户访问客户源服务器时间超过自定义失效时间(timestamp字段指定)的1800s后,该鉴权失效</p>
 * <p>例如用户设置访问时间为2020-08-15 15:00:00,则链接的真正失效时间为2020-08-15 15:30:00。</p>
 * <p>url中特殊字符进行转码,避免中文路径异常</p>
 * @author douhuatong
 * @since 2019-03-06 15:02
public class AliyunCndUrlAccessUtil {
  static final String ENCODING = "utf-8";
  private static final DateTimeFormatter YYYYMMDDHHMM = DateTimeFormatter.ofPattern("yyyyMMddHHmm");
  private static final String hexDigIts[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
   * A方式鉴权
   * <P>https://help.aliyun.com/document_detail/85113.html?spm=a2c4g.11186623.6.604.5d708d48FTiaa8</P>
   * 用户访问的 URL 如下: http://cdn.example.com/video/standard/1K.html?auth_key=1444435200-0-0-80cd3862d699b7118eed99103f2a3a4f
   * @param domainName cnd域名
   * @param privateKey cnd 加密key
   * @param objectKey oss 对象key  (注意,鉴权时候 objectKey 要以/开头)
   * @param expiration 过期时间
  public static String signA(String domainName, String privateKey, String objectKey, Date expiration) {
    if (isBlank(objectKey)) {
      return "";
    long es = expiration.getTime() / 1000;
    String rand = UUID.randomUUID().toString().replace("-", "");
    try {
      objectKey = URLEncoder.encode(objectKey, ENCODING).replace("%2F", "/");
    } catch (UnsupportedEncodingException e) {
    if (!objectKey.startsWith("/")) {
      objectKey = "/" + objectKey;
    return domainName + objectKey + "?auth_key=" + es + "-" + rand + "-0-" + md5Hex(objectKey + "-" + es + "-" + rand + "-0-" + privateKey);
   * B方式鉴权
   * <P>https://help.aliyun.com/document_detail/85114.html?spm=a2c4g.11186623.6.596.705c100bXExQvg</P>
   * 用户访问的 URL 如下: 试用 http://DomainName/timestamp/md5hash/FileName 加密URL的构造:域名后跟生成URL的时间(精确到分钟)(timestamp)再跟md5值(md5hash),最后拼接回源服务器的真实路径(FileName),URL有效时间为1800s。
   * 当鉴权通过时,实际回源的URL是: 试用 http://DomainName/FileName
   * URL有效时间为1800s。
   * @param domainName cnd域名
   * @param privateKey cnd 加密key
   * @param objectKey oss 对象key  (注意,鉴权时候 objectKey 要以/开头)
   * @param expiration 过期时间
  public static String signB(String domainName, String privateKey, String objectKey, Date expiration) {
    if (isBlank(objectKey)) {
      return "";
    try {
      objectKey = URLEncoder.encode(objectKey, ENCODING).replace("%2F", "/");
    } catch (UnsupportedEncodingException e) {
    if (!objectKey.startsWith("/")) {
      objectKey = "/" + objectKey;
    LocalDateTime localDateTime = LocalDateTime.ofInstant(expiration.toInstant(), ZoneId.systemDefault());
    String now = localDateTime.format(YYYYMMDDHHMM);
    return domainName + "/" + now + "/" + md5Hex(privateKey + now + objectKey) + objectKey;
   * C方式鉴权 1
   * <P>https://help.aliyun.com/document_detail/85115.html?spm=a2c4g.11186623.6.606.5d708d481mQzCF</P>
   * 用户访问的 URL http://DomainName/{/}/FileName
   * @param domainName cnd域名
   * @param privateKey cnd 加密key
   * @param objectKey oss 对象key  (注意,鉴权时候 objectKey 要以/开头)
   * @param expiration 过期时间
  public static String signC1(String domainName, String privateKey, String objectKey, Date expiration) {
    if (isBlank(objectKey)) {
      return "";
    try {
      objectKey = URLEncoder.encode(objectKey, ENCODING).replace("%2F", "/");
    } catch (UnsupportedEncodingException e) {
    if (!objectKey.startsWith("/")) {
      objectKey = "/" + objectKey;
    String time = new BigInteger(String.valueOf(expiration.getTime() / 1000), 10).toString(16);
    String md5 = md5Hex(privateKey + objectKey + time);
    return domainName + "/" + md5 + "/" + time + objectKey;
   * C方式鉴权 2
   * <P>https://help.aliyun.com/document_detail/85115.html?spm=a2c4g.11186623.6.606.5d708d481mQzCF</P>
   * 用户访问的 URL http://cdn.example.com/a37fa50a5fb8f71214b1e7c95ec7a1bd/55CE8100/test.flv
   * @param domainName cnd域名
   * @param privateKey cnd 加密key
   * @param objectKey oss 对象key
   * @param expiration 过期时间
  public static String signC2(String domainName, String privateKey, String objectKey, Date expiration) {
    if (isBlank(objectKey)) {
      return "";
    try {
      objectKey = URLEncoder.encode(objectKey, ENCODING).replace("%2F", "/");
    } catch (UnsupportedEncodingException e) {
    if (!objectKey.startsWith("/")) {
      objectKey = "/" + objectKey;
    String time = new BigInteger(String.valueOf(expiration.getTime() / 1000), 10).toString(16);
    String md5 = md5Hex(privateKey + objectKey + time);
    return domainName + objectKey + "?KEY1=" + md5 + "&KEY2=" + time;
  public static boolean isBlank(final CharSequence cs) {
    int strLen;
    if (cs == null || (strLen = cs.length()) == 0) {
      return true;
    for (int i = 0; i < strLen; i++) {
      if (!Character.isWhitespace(cs.charAt(i))) {
        return false;
    return true;
  private static String md5Hex(String origin) {
    String resultString = null;
    try {
      MessageDigest md = MessageDigest.getInstance("MD5");
      resultString = byteArrayToHexString(md.digest(origin.getBytes(ENCODING)));
    } catch (Exception e) {
    return resultString;
  private static String byteArrayToHexString(byte[] b) {
    StringBuilder resultSb = new StringBuilder();
    for (byte b1 : b) {
      resultSb.append(byteToHexString(b1));
    return resultSb.toString();
  private static String byteToHexString(byte b) {
    int n = b;
    if (n < 0) {
      n += 256;
    int d1 = n / 16;
    int d2 = n % 16;
    return hexDigIts[d1] + hexDigIts[d2];
  public static void main(String[] args) {
    String key = "123";
    String domain = "http://xxx.aaa.com";
    String ossKey = "xxx.pdf";
    System.err.println("A=:   " + signA(domain, key, ossKey, new Date()));
    System.err.println("B=:   " + signB(domain, key, ossKey, new Date()));
    System.err.println("C-1=:   " + signC1(domain, key, ossKey, new Date()));
    System.err.println("C-2=:   " + signC2(domain, key, ossKey, new Date()));