1. 程式人生 > >阿里雲視訊直播API簽名機制原始碼

阿里雲視訊直播API簽名機制原始碼

阿里雲視訊直播API簽名機制原始碼

本文展示:通過程式碼實現下阿里視訊直播簽名處理規則

 

阿里雲視訊直播簽名機制,官方文件連結:https://help.aliyun.com/document_detail/50286.html?spm=a2c4g.11186623.2.11.2a053653zSTuUw#concept-50286-zh

官方文件說明如下:

您在訪問時,需要按照下面的方法對請求進行簽名處理。

  1. 使用請求引數構造規範化的請求字串(Canonicalized Query String)。
    1. 引數排序。 按照引數名稱的字典順序對請求中所有的請求引數(包括“公共請求引數”和介面的自定義引數,但不包括“公共請求引數”中的  Signature
       引數)進行排序。 說明 當使用 GET 方法提交請求時,這些引數就是請求 URI 中的引數部分(即 URI 中“?”之後由“&”連線的部分)。
    2. 引數編碼。 對排序之後的請求引數的名稱和值分別用 UTF-8 字符集進行 URL 編碼。編碼的規則如下。
      • 對於字元 A~Z、a~z、0~9 以及字元“-”、“_”、“.”、“~”不編碼;

      • 對於其它字元編碼成 %XY 的格式,其中 XY

         是字元對應 ASCII 碼的 16 進製表示。比如英文的雙引號(”)對 應的編碼為 %22

      • 對於擴充套件的 UTF-8 字元,編碼成 %XY%ZA… 的格式;

      • 英文空格( )要編碼成 %20,而不是加號(+)。

        該編碼方式和一般採用的 application/x-www-form-urlencoded MIME 格式編碼演算法(比如 Java 標準庫中的 java.net.URLEncoder 的實現)相似,但又有所不同。實現時,可以先用標準庫的方式進行編碼,然後把編碼後的字串中加號(+)替換成 %20

        、星號(*)替換成 %2A%7E 替換回波浪號(~),即可得到上述規則描述的編碼字串。這個演算法可以用下面的 percentEncode 方法來實現:

        private static final String ENCODING = "UTF-8";
        
        private static String percentEncode(String value) throws UnsupportedEncodingException {
        return value != null ? URLEncoder.encode(value, ENCODING).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null; } 
    3. 將編碼後的引數名稱和值用英文等號(=)進行連線。
    4. 將等號連線得到的引數組合按步驟 i 排好的順序依次使用“&”符號連線,即得到規範化請求字串。
  2. 將上一步構造的規範化字串按照下面的規則構造成待簽名的字串。
    StringToSign=
    HTTPMethod + “&” +
    percentEncode(“/”) + ”&” +
    percentEncode(CanonicalizedQueryString) 
    其中:
    • HTTPMethod 是提交請求用的 HTTP 方法,比如 GET。

    • percentEncode(“/”) 是按照步驟 1.ii 中描述的 URL 編碼規則對字元 “/” 進行編碼得到的值,即 %2F。

    • percentEncode(CanonicalizedQueryString) 是對步驟 1 中構造的規範化請求字串按步驟 1.ii 中描述的 URL 編碼規則編碼後得到的字串。

  3. 按照 RFC2104 的定義,計算待簽名字串 StringToSign 的 HMAC 值。 說明 計算簽名時使用的 Key 就是您持有的 Access Key Secret 並加上一個 “&” 字元(ASCII:38),使用的雜湊演算法是 SHA1。
  4. 按照 Base64 編碼規則把上面的 HMAC 值編碼成字串,即得到簽名值(Signature)。
  5. 將得到的簽名值作為 Signature 引數新增到請求引數中,即完成對請求籤名的過程。說明 得到的簽名值在作為最後的請求引數值提交給視訊直播伺服器的時候,要和其他引數一樣,按照 RFC3986的規則進行 URL 編碼)。

 

根據官方文件,原始碼實現如下:

    
package com.hs.common.alilive;

import sun.misc.BASE64Encoder;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

public class AliLiveSignatureUtil {


    public static final String Format = "JSON";
    public static final String VERSION = "2016-11-01";
    public static final String AccessKeyId = "testkey";//填寫你的key
    public static final String AccessKeySecret = "testsecret";//填寫你的Secret
   // public static final String Signature = "";
    public static final String SignatureMethod = "HMAC-SHA1";
    // public static final String Timestamp = getUTCTimeStr();
    public static final String SignatureVersion = "1.0";
    // public static final String SignatureNonce = RandomStringUtils.randomAlphanumeric(12);

    private static final String ISO8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";


    //1-根據請求引數Map獲取簽名
    public  static String getSignatureFromParam(Map<String,String> paramMap) {
        //Map<String,String> paramMap封裝了具體api的私有引數和公有引數,key和value
     String signature = "";
        try {
            final String SEPARATOR = "&";
            //1-獲取請求引數構造規範化的請求字串(Canonicalized Query String)
            //1-1-對引數進行排序
            String[] sortedKeys = (String[]) paramMap.keySet().toArray(new String[]{});
            Arrays.sort(sortedKeys);
            //1-2-引數編碼、引數名稱和值用英文等號(=)進行連線、使用“&”符號連線,即得到規範化請求字串,
            //這裡將引數編碼、英文等號(=)連線、使用“&”符號連線三步一起放在迴圈裡面進行操作
            StringBuilder canonicalizedQueryString = new StringBuilder();
            for (String key : sortedKeys) {
                canonicalizedQueryString.append("&").append(percentEncode(key))
                        .append("=").append(percentEncode((String) paramMap.get(key)));
            }

            //2-將上一步構造的規範化字串按照下面的規則構造成待簽名的字串(注意percentEncode的使用)。
            //HTTPMethod 是提交請求用的 HTTP 方法,比如 GET。
            //percentEncode(“/”) 是按照步驟 1.ii 中描述的 URL 編碼規則對字元 “/” 進行編碼得到的值,即 %2F。
            //percentEncode(CanonicalizedQueryString) 是對步驟 1 中構造的規範化請求字串按步驟 1.ii 中描述的 URL 編碼規則編碼後得到的字串。
            StringBuilder stringToSign = new StringBuilder();
            stringToSign.append("GET").append(SEPARATOR).append(percentEncode("/")).append(SEPARATOR);
            stringToSign.append(percentEncode(canonicalizedQueryString.toString()
                    .substring(1)));
            System.out.println(stringToSign);

            //3- 按照 RFC2104 的定義,計算待簽名字串 StringToSign 的 HMAC 值。
            //計算簽名時使用的 Key 就是您持有的 Access Key Secret 並加上一個 “&” 字元(ASCII:38),使用的雜湊演算法是 SHA1。()
            //final String ALGORITHM = "HMAC-SHA1";//注意使用HMAC-SHA1會報錯,要用HmacSHA1(但是我看的參考部落格用的是“HMAC-SHA1”)
            final String ALGORITHM = "HmacSHA1";
            final String ENCODING = "UTF-8";
            String key = AccessKeySecret + "&";
            Mac mac = Mac.getInstance(ALGORITHM);
            mac.init(new SecretKeySpec(key.getBytes(ENCODING), ALGORITHM));
            byte[] signData = mac.doFinal(stringToSign.toString().getBytes(ENCODING));

            //4-按照 Base64 編碼規則把上面的 HMAC 值編碼成字串,即得到簽名值(Signature)。
            signature = new String(new BASE64Encoder().encode(signData));
            signature = percentEncode(signature);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
        return signature;
    }
    
    //1-1-轉碼
    private static String percentEncode(String value) throws UnsupportedEncodingException {
        return value != null ? URLEncoder.encode(value, "utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null;

    }

    //1-2-獲取時間
    private static String getUTCTimeStr() {
        //1、取得本地時間:
        final Calendar cal = Calendar.getInstance();
        System.out.println(cal.getTime());
        //2、取得時間偏移量:
        final int zoneOffset = cal.get(Calendar.ZONE_OFFSET);
        System.out.println(zoneOffset);
        //3、取得夏令時差:
        final int dstOffset = cal.get(Calendar.DST_OFFSET);
        System.out.println(dstOffset);
        //4、從本地時間裡扣除這些差量,即可以取得UTC時間:
        cal.add(Calendar.MILLISECOND, -(zoneOffset + dstOffset));
        SimpleDateFormat df = new SimpleDateFormat(ISO8601_DATE_FORMAT);
        return df.format(cal.getTime());
    }
}

 

 

參考資料:

1-https://blog.csdn.net/u010904352/article/details/53737625