签名机制

更新时间:2023-05-22 06:38:11下载pdf

发送 API 调用请求时,API 网关 要求应用提供签名(Sign)进行身份验证。本文介绍如何构建 API 签名。

签名算法

API 网关采用 HMAC SHA256 方法创建摘要。您可以通过 Postman 软件,自行校验 API 请求中 sign 的加密结果。关于校验方法,查看 验证签名结果

为了提供更安全的服务,API 网关对签名算法进行了升级。在 2021 年 6 月 30 日之后创建的新项目仅支持使用新算法验签。2021 年 6 月 30 日前创建的项目仍可使用旧版签名机制。但是,基于信息安全考虑,建议您修改为新的签名算法。

令牌管理 API

  • 适用范围:获取令牌和刷新令牌 API。

  • 签名算法:

    sign = HMAC-SHA256(client_id + t + nonce + stringToSign, secret).toUpperCase()
    
  • 算法逻辑:

    1. nonce 为您生成的 UUID,结合时间戳防重复,nonce 为非必填字段。stringToSign 为签名字符串。
    2. client_id 与当前请求的 13 位标准时间戳(t)、noncestringToSign 拼接成字符串。
    3. 将字符串和 secret 进行哈希摘要,得到新的字符串。
    4. 将新的字符串转为大写。

业务管理 API

  • 适用范围:令牌管理接口以外的其他 API。

  • 签名算法:

    str = client_id + access_token + t + nonce + stringToSign
    sign = HMAC-SHA256(str, secret).toUpperCase()
    
  • 算法逻辑:

    1. nonce 为您生成的 UUID,结合时间戳防重复,nonce 为非必填字段。stringToSign 为签名字符串。
    2. client_idaccess_token、当前请求的 13 位标准时间戳(t)、noncestringToSign 拼接成字符串。
    3. 将字符串和 secret 进行哈希摘要,得到新的字符串。
    4. 将新的字符串转为大写。

stringToSign 签名字符串

  • 组成部分:

    String stringToSign=
    HTTPMethod + "\n" +
    Content-SHA256 + "\n" +
    Headers + "\n" +
    Url
    
  • 签名字符串字段:

    1. HTTPMethod 为全大写,如 POSTPUT 等。

    2. Content-SHA256 是指请求 Body 的 SHA256 值。只有当 Body 非 Form 表单时,才计算 SHA256,计算方式如下:

      String content-SHA256 = SHA256(bodyStream.getbytes("UTF-8")); //bodyStream 为字节数组
      

      当 Body 为空时,也会进行加密,加密结果为 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

    3. Headers 是指参与签名计算的 Header 的字段(Key)和字段取值(Value)拼接的字符串。

      您需要将参与签名的 Header 的字段拼接到一起,用半角冒号(:)分隔,作为 Signature-Headers 的值。Header 格式如下:

      client_id:xxx
      Signature-Headers : Key1:Key2
      Key1:xxx
      Key2:xxx
      key3:xxx (不会加到签名计算中)
      nonce:xxx
      ·····
      

      如果只计算出现在 Signature-Headers 里面的 Key,则如下所示:

      String Headers =
      HeaderKey1 + ":" + HeaderValue1 + "\n" +
      HeaderKey2 + ":" + HeaderValue2 + "\n" +
      ...
      HeaderKeyN + ":" + HeaderValueN + "\n"
      
    4. URL 指 Path、Query、Body 中 Form 参数。

      对 Query+Form 参数按照字典对 Key 进行排序后,按照如下方法拼接,如果 Query 或 Form 参数为空,则 URL=Path,不需要添加?

      String url =
      Path +
      "?" +
      Key1 + "=" + Value1 +
      "&" + Key2 + "=" + Value2 +
      "&" + Key3 +
      ...
      "&" + KeyN + "=" + ValueN
      

签名示例

示例参数

获取用户列表 API 为例,schema 参数为 apps,无 body 参数。

接口调用请求头(Request Header)参数,请参考 请求结构

参数 取值
URL /v2.0/apps/schema/users
method GET
client_id 1KAD46OrT9HafiKdsXeg
secret 4OHBOnWOqaEC1mWXOpVL3yV50s0qGSRC
t 1588925778000
access_token 3f4eda2bdec17232f67c0b188af3eec1
sign_method HMAC-SHA256
说明:签名的摘要算法,请求头必须添加。
nonce 5138cc3a9033d69856923fd07b491173
Signature-Headers area_id:call_id
area_id (开发者自定义) 29a33e8796834b1efa6
call_id (开发者自定义) 8afdb70ab2ed11eb85290242ac130003
page_no 1
page_size 50

令牌管理 API 签名

  1. 拼接 stringToSign 签名字符串。

    stringToSign=GET
    e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    area_id:29a33e8796834b1efa6
    call_id:8afdb70ab2ed11eb85290242ac130003
    
    /v1.0/token?grant_type=1
    
  2. 拼接待签名字符串。

    1KAD46OrT9HafiKdsXeg15889257780005138cc3a9033d69856923fd07b491173GET
    e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    area_id:29a33e8796834b1efa6
    call_id:8afdb70ab2ed11eb85290242ac130003
    
    /v1.0/token?grant_type=1
    
  3. 通过哈希摘要获得新字符。

    • 哈希摘要:

      HMAC-SHA256(1KAD46OrT9HafiKdsXeg15889257780005138cc3a9033d69856923fd07b491173GET
      e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
      area_id:29a33e8796834b1efa6
      call_id:8afdb70ab2ed11eb85290242ac130003
      
      /v1.0/token?grant_type=1,4OHBOnWOqaEC1mWXOpVL3yV50s0qGSRC)
      
    • 新字符:

      9e48a3e93b302eeecc803c7241985d0a34eb944f40fb573c7b5c2a82158af13e
      
  4. 转换为大写。

    9E48A3E93B302EEECC803C7241985D0A34EB944F40FB573C7B5C2A82158AF13E
    

业务管理 API 签名

  1. 拼接 stringToSign 签名字符串。

    stringToSign=GET
    e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    area_id:29a33e8796834b1efa6
    call_id:8afdb70ab2ed11eb85290242ac130003
    
    /v2.0/apps/schema/users?page_no=1&page_size=50
    
  2. 拼接待签名字符串。

    1KAD46OrT9HafiKdsXeg3f4eda2bdec17232f67c0b188af3eec115889257780005138cc3a9033d69856923fd07b491173GET
    e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
    area_id:29a33e8796834b1efa6
    call_id:8afdb70ab2ed11eb85290242ac130003
    
    /v2.0/apps/schema/users?page_no=1&page_size=50
    
  3. 通过哈希摘要获得新字符。

    • 哈希摘要:

      HMAC-SHA256(1KAD46OrT9HafiKdsXeg3f4eda2bdec17232f67c0b188af3eec115889257780005138cc3a9033d69856923fd07b491173GET
      e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
      area_id:29a33e8796834b1efa6
      call_id:8afdb70ab2ed11eb85290242ac130003
      
      /v2.0/apps/schema/users?page_no=1&page_size=50,4OHBOnWOqaEC1mWXOpVL3yV50s0qGSRC)
      
    • 新字符:

      ae4481c692aa80b25f3a7e12c3a5fd9bbf6251539dd78e565a1a72a508a88784
      
  4. 转换为大写。

    AE4481C692AA80B25F3A7E12C3A5FD9BBF6251539DD78E565A1A72A508A88784
    

HMAC SHA256 实现

Java 示例

单击下载 Java 代码示例

Go 示例

单击下载 Go 代码示例

Node.js 示例

单击下载 Node.js 代码示例

Javascript 示例

/**
Run the code online with this jsfiddle. Dependent upon an open source js library calledhttp://code.google.com/p/crypto-js/.
**/

<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/enc-base64.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/hmac-sha256.min.js"></script>

<script>
  var hash = CryptoJS.HmacSHA256("Message", "secret");
  var hashInBase64 = hash.toString().toUpperCase();
  document.write(hashInBase64);
</script>

PHP 示例

/**
PHP has built in methods for hash_hmac (PHP 5) and base64_encode (PHP 4, PHP 5) resulting in no outside dependencies. Say what you want about PHP but they have the cleanest code for this example.
**/

$s = strtoupper(hash_hmac("sha256", "Message", 'secret'));
echo var_dump($s);

C# 示例

using System;
using System.Security.Cryptography;

namespace Test
{
  public class MyHmac
  {
    public static string Encrypt(string message, string secret)
            {
                secret = secret ?? "";
                var encoding = new System.Text.UTF8Encoding();
                byte[] keyByte = encoding.GetBytes(secret);
                byte[] messageBytes = encoding.GetBytes(message);
                using (var hmacsha256 = new HMACSHA256(keyByte))
                {
                    byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
                    StringBuilder builder = new StringBuilder();
                    for (int i = 0; i < hashmessage.Length; i++)
                    {
                        builder.Append(hashmessage[i].ToString("x2"));
                    }
                    return builder.ToString().ToUpper();
                }
            }
  }
}

常见问题

如何验证加密后的签名?

本地开发时,可用基于 Postman 软件预先查看加密后的签名结果。查询方法请参考 验证签名结果