介绍生活物联网平台在开发中用到的加签算法。

操作步骤

  1. 构建加密字符串。
    String stringToSign= 
    HTTPMethod + "\n" + 
    Accept + "\n" + //建议显示设置 Accept Header。当 Accept 为空时,部分 Http 客户端会给 Accept 设置默认值为 */*,导致签名校验失败。
    Content-MD5 + "\n" 
    Content-Type + "\n" + 
    Date + "\n" + 
    Headers + 
    Url

    其中,HTTPMethod为全大写,如 POST。AcceptContent-MD5Content-TypeDate如果为空也需要添加换行符 ”\n”Headers如果为空不需要添加 ”\n”

    • Content-MD5

      Content-MD5是指Body的MD5值,只有当Body非Form表单时才计算 MD5,计算方式如下。

      String content-MD5 = Base64.encodeBase64(MD5(bodyStream.getbytes("UTF-8"))); //bodyStream为字节数组
    • Headers

      Headers是指参与Headers签名计算的Header的Key、Value拼接的字符串,建议对 X-Ca 开头的Header和自定义Header计算签名。

      说明 以下参数不参与Headers签名计算:X-Ca-Signature、X-Ca-Signature-Headers、Accept、Content-MD5、Content-Type、Date。

      Headers组织方法如下。

      对参与签名计算的Header的Key按照字典排序后使用。如果某个Header的Value为空,则使用HeaderKey + “:”+“\n”参与签名,需要保留Key和英文冒号。示例如下所示。

      String headers =
      HeaderKey1 + ":" + HeaderValue1 + "\n"\+
      HeaderKey2 + ":" + HeaderValue2 + "\n"\+
      ...
      HeaderKeyN + ":" + HeaderValueN + "\n"

      将Headers签名中Header的Key使用英文逗号分割放到Request的Header中,Key为:X-Ca-Signature-Headers。

    • URL

      URL指Path+Query+Body中Form参数,组织方法如下。

      对Query+Form参数按照字典对Key进行排序后,按照如下方法拼接,如果Query或Form参数为空,则URL=Path,不需要添加,如果某个参数的Value为空只保留Key参与签名,等号则不需要再加入签名。

      String url =
      Path +
      "?" +
      Key1 + "=" + Value1 +
      "&" + Key2 + "=" + Value2 +
      ...
      "&" + KeyN + "=" + ValueN
      							
      说明 QueryForm参数的Value可能有多个,多个的时候只取第一个Value参与签名计算。
  2. 计算签名。
    Mac hmacSha256 = Mac.getInstance("HmacSHA256");
    byte[] keyBytes = secret.getBytes("UTF-8");
    hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, "HmacSHA256"));
    String sign = new String(Base64.encodeBase64(hmacSha256.doFinal(stringToSign.getBytes("UTF-8")),"UTF-8"));

    其中,secret为App的密钥。

  3. 传递签名。
    将计算的签名结果放到 Request 的 Header 中,Key为:X-Ca-Signature。
  4. 排查签名错误。
    当签名校验失败时,API网关会将服务端的StringToSign放到HTTP Response的Header中返回到客户端,Key为:X-Ca-Error-Message,只需要将本地计算的StringToSign与服务端返回的StringToSign进行对比即可找到问题。

    如果服务端与客户端的StringToSign一致请检查用于签名计算的密钥是否正确。因为HTTP Header中无法表示换行,因此StringToSign中的换行符都被过滤掉了,对比时请忽略换行符。

  5. 签名demo。
    签名计算的详细 demo(JAVA)请参照链接:https://github.com/aliyun/api-gateway-demo-sign-java