
# 回调接口说明
- 座席双呼的接通回调URL只有一种配置方式，通过界面配置：租户管理员选择"配置中心 \> 扩展与集成 \> 双呼"，设置"接通回调url"。
- 座席双呼的挂机回调URL有两种配置方式：
  1. 通过界面配置：租户管理员选择"配置中心 \> 扩展与集成 \> 双呼"，设置"挂机回调url"。
  
  
  
  2. 通过创建呼叫 (V1.0.0)接口传入：调用创建呼叫 (V1.0.0)接口时传入请求参数callBackUrl。
  
  
  ![](https://support.huaweicloud.com/api-ccfs-cec/public_sys-resources/note_3.0-zh-cn.png)
  - 通过界面配置挂机回调URL的方式，URL鉴权方式为不鉴权，不鉴权可能有安全风险，请谨慎使用。
  
  - 如果两种方式都配置了挂机回调URL，将选择通过创建呼叫 (V1.0.0)接口传入的callBackUrl。
    
#### 座席双呼回调接口签名算法说明
- **签名算法（鉴权）使** **用前** **提** **条件**
  当通过创建呼叫 (V1.0.0)接口传入挂机回调URL，并在回调url配置界面中"请选择回调URL鉴权方式"选择了"共享密钥签名"，请参考本节进行签名验证。
  

- **鉴权过程**
  1. 系统在挂机回调URL时，如果符合签名条件，接口入参会添加以下字段： timestamp：当前时间戳，
     nonce：随机字符串，
     signature：鉴权签名。
     
  
  2. 客户侧收到回调后，需要根据签名算法生成鉴权签名，并与入参的signature进行校验，若一致表示验证通过。
   

- **签名（signature）字符串生成方式** ：
  1. 根据参数名称对所有的请求参数（除这三个参数外：timestamp、nonce、signature）进行字典排序，然后用英文逗号拼接成字符串。例如将{"b":"2", "a":1, "d":"null", "c":""}排序拼接为"a=1,b=2,c=,d=null"。
  
  2. 生成timestamp时间戳及nonce随机字符串，并和appSecret（界面配置的"共享密钥签名"）及[1]生成的字符串通过 _ 拼接在一起。格式为 appSecret_timestamp_nonce_[1]生成的字符串。
  
  3. 通过SHA256算法加密成byte数组，然后将该数组Base64编码。
   
- **参考代码**
  ```
  import javax.crypto.Mac;
  import javax.crypto.spec.SecretKeySpec;
  private String generateSinature(TreeMap<String, Object> callbackParametters, String nonce, long timestamp, String appSecret) {
      // appSecret_timestamp_nonce_参数
      // {"b":"2", "a":1, "d":"null", "c":""}排序拼接后的字符串是："a=1,b=2,c=,d=null"
      String paramStr = callbackParametters.toString().replace(" ", "");
      String toSignString = appSecret + "_" + timestamp + "_" + nonce + "_" + 
             paramStr.substring(1， paramStr.length() - 1);
      return Base64.encodeBase64String(tokenByHmacSha256(toSignString.getBytes(StandardCharsets.UTF_8), appSecret));
  }
  public static byte[] tokenByHmacSha256(byte[] dataBytes, String appSecret) {
      try {
          Mac mac = Mac.getInstance("HmacSHA256");
          byte[] key = appSecret.getBytes(StandardCharsets.UTF_8);
          SecretKeySpec secretKey = new SecretKeySpec(key, "HmacSHA256");
          mac.init(secretKey);return mac.doFinal(dataBytes);
      } catch (Exception e) {
          LOGGER.error("tokenByHmacSha256 failed: ", e);throw new RuntimeException("HmacSha256 run failed.");
      }
  }
  ```
  
 
