日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

簽名計算使用指引

簽名機制

為保證 HTTP/HTTPS 服務的安全使用,在服務配置中可選擇開啟簽名計算,在調用 API 時全局服務會對開啟簽名的服務進行簽名計算,并將簽名放到請求header中。本文介紹計算簽名的方法和示例。

步驟一:拼接不同請求類型的參數

1、CanonicalizedHeaderString:

(1)header參數范圍:包括header中以“x-dmpaas”開頭的系統參數、header自定義參數,不包括header參數中的x-dmpaas-signature參數。

(2)header參數排序和拼接:

按照參數字符串字典升序對header參數排序,多個header之間用&連接。

使用等號(=)連接編碼后的header參數和編碼后的header參數值,編碼方式參考附錄。

2、CanonicalizedQueryString:

(1)query參數范圍:全局服務頁面上所有query參數、URL連接串提前預置的query參數

(2)query參數排序和拼接:

使用等號(=)連接編碼后的query參數和編碼后的query參數值,編碼方式參考附錄。

按照參數字符串字典升順對query參數排序,多個query之間用&連接。

3、CanonicalizedBodyString:請求的body 字符串,如果沒有body,就用空字符串("");

步驟二:構造簽名字符串

我們以 Java 為例,該字符串構造規則如下:

String stringToSign =

HTTPMethod + "&" +

encodeURIComponent("/") + "&" +

encodeURIComponent(CanonicalizedHeaderString) + "&" +

encodeURIComponent(CanonicalizedQueryString) + "&" +

encodeURIComponent(CanonicalizedBodyString)

步驟三:計算簽名

在全局服務配置中可查到AccessKey匹配的AccessToken,作為加密的密鑰,使用 HMAC-SHA1 的簽名算法,計算待簽名字符串StringToSign的簽名。

參考代碼

通過`ChatbotSignUtil.checkSign()`進行驗簽。

  • 對于請求頭,在驗簽過程中,僅關注以“x-dmpaas”開頭的系統參數和“全局服務/API插件-編輯-header參數”中配置的header,其他header需要在驗簽前移除。

  • 特別注意:在進行GET請求時,body一定為null。

import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

public class ChatbotSignUtil {
    /**
     * 簽名密鑰對,可以從“全局服務/API插件-編輯-啟用簽名”中獲取
     */
    public static final String ACCESS_KEY = "yourAccessKey";
    public static final String ACCESS_TOKEN = "yourAccessToken";
    /**
     * chatbot所需header
     */
    public static final String HTTP_CHATUUID_HEADER = "x-dmpaas-beebot-chat-id";
    public static final String HTTP_TIMESTAMP_HEADER = "x-dmpaas-timestamp";
    public static final String HTTP_ACCESSKEY_HEADER = "x-dmpaas-accesskey";
    public static final String HTTP_SIGNATURE_NONCE_HEADER = "x-dmpaas-signature-nonce";
    public static final String HTTP_SIGNATURE_HEADER = "x-dmpaas-signature";

    public static final String ENCODING = "UTF-8";
    public static final String SIGN_ALGORITHM = "HmacSHA1";

    /**
     * 校驗簽名。
     * @param method        請求方法,GET/POST。
     * @param requestParams 請求參數,無論是GET還是POST,requestParams中均有參數。
     * @param headers       請求頭,其中包含chatbot所需要的header和業務所需的header,其他header需要過濾掉。
     * @param body          請求體,如果是GET請求,則body為null,如果是POST請求,則body為json格式的請求體。
     * @throws Exception 簽名校驗失敗拋出異常。
     */
    public static void checkSign(String method, Map<String, String> requestParams,
        Map<String, String> headers, String body) throws Exception {
        // 根據入參生成簽名
        String signString = getSignatureString(method, headers, requestParams, body);
        // 校驗生成的簽名和傳入的簽名是否一致
        String signature = headers.getOrDefault(HTTP_SIGNATURE_HEADER, null);
        if (!signString.equals(signature)) {
            throw new RuntimeException("簽名不一致");
        }
        System.out.println("簽名校驗通過");
    }

    public static String getSignatureString(String method, Map<String, String> headerParams,
        Map<String, String> queryParams, String body) throws Exception {
        //1.注意:header僅包含上方名為"x-dmpaas-***"的header和“api插件-編輯-header參數”中配置的header
        TreeMap<String, Object> headerTreeMap = new TreeMap<>(headerParams);
        //2.HTTP_SIGNATURE_HEADER要排除掉
        headerTreeMap.remove(HTTP_SIGNATURE_HEADER);
        //3.構造header和query的規范化簽名字符串
        TreeMap<String, Object> queryTreeMap = new TreeMap<>(queryParams);
        StringBuilder headerStr = new StringBuilder();
        StringBuilder queryStr = new StringBuilder();
        for (String key : headerTreeMap.keySet()) {
            headerStr.append("&").append(specialCharUrlEncode(key)).append("=").append(
                specialCharUrlEncode(headerTreeMap.get(key).toString()));
        }
        for (String key : queryTreeMap.keySet()) {
            queryStr.append("&").append(specialCharUrlEncode(key)).append("=").append(
                specialCharUrlEncode(queryTreeMap.get(key).toString()));
        }
        //拼接完要將第一個&去掉,拼接上body
        String canonicalizedHeaderString;

        if (headerTreeMap.isEmpty()) {
            canonicalizedHeaderString = "";
        } else {
            canonicalizedHeaderString = headerStr.substring(1);
        }
        System.out.println("canonicalizedHeaderString: " + canonicalizedHeaderString);
        String canonicalizedQueryString;
        if (queryTreeMap.isEmpty()) {
            canonicalizedQueryString = "";
        } else {
            canonicalizedQueryString = queryStr.substring(1);
        }
        System.out.println("canonicalizedQueryString: " + canonicalizedQueryString);
        //4.拼接出構造密鑰所需的加密前字符串
        //specialCharUrlEncode,對特殊字符進行替換,例如空格編碼成%20
        String stringToSign = method + "&" + specialCharUrlEncode("/") + "&" +
            specialCharUrlEncode(canonicalizedHeaderString) + "&" +
            specialCharUrlEncode(canonicalizedQueryString) + "&" +
            specialCharUrlEncode(body);
        System.out.println("stringToSign: " + stringToSign);
        //5.使用accessToken構造密鑰secret
        String accessKey = headerParams.get(HTTP_ACCESSKEY_HEADER);
        if (!ACCESS_KEY.equals(accessKey)) {
            throw new RuntimeException("ERROR accessKey");
        }
        String secret = ACCESS_TOKEN + "&";
        System.out.println("secret: " + secret);
        return doSignature(stringToSign, secret, SIGN_ALGORITHM);
    }

    private static String specialCharUrlEncode(String value) throws UnsupportedEncodingException {
        if (value == null || value.isEmpty()) {
            return "";
        }
        //調用中,需要對請求參數和請求值使用 UTF-8 字符集按照RFC3986規則進行編碼。
        return java.net.URLEncoder.encode(value, ENCODING).replace("+", "%20")
            .replace("*", "%2A").replace("%7E", "~");
    }

    private static String doSignature(String stringToSign, String secret, String signAlgorithm) throws Exception {
        SecretKeySpec signinKey = new SecretKeySpec(secret.getBytes(ENCODING), signAlgorithm);
        Mac mac = Mac.getInstance(signAlgorithm);
        mac.init(signinKey);
        return DatatypeConverter.printBase64Binary(mac.doFinal(stringToSign.getBytes(ENCODING)));
    }
}