# 回调接入指南

## 一、接入必读
- 对接前需要在下图所示位置进行配置并提交保存，通过对应接口要求的信息与SCRM系统交互；
- 当尘锋系统内的联系人、企业、旅程、订单等业务内容发生变更时，支持推送变更事件给您，您需要在`“设置-系统对接”`页面完成 `消息校验token、消息加解密key、消息与事件接受URL、调用数据加解密` 四个参数的配置；

![WX20241230-191711@2x.png](https://api.apifox.com/api/v1/projects/4227827/resources/487180/image-preview)
- 【加密解密】<span style="color:red;">密文数据仅用于</span>尘锋SCRM系统联系人管理部分接口<span style="color:red;">主动向第三方系统服务端推送变更事件</span>；
:::caution[]
1、调用数据加密不论是否开启，在初次配置消息与事件接受URL时，均需要实现完整的数据解密逻辑，解密逻辑可参考本文《三、URL配置校验（GET请求）-2、三方系统-URL配置校验解密示例》
2、如暂时不确定对SCRM系统发起请求的服务器出口IP或者其他情况，可先设置为`0.0.0.0`调试,后期根据第三方系统的实际情况进行调整；
3、OpenAPI进行新增和编辑等操作不会触发对应事件变更回调
:::

## 二、配置回调URL、加密参数

- **【消息与事件接受URL**】：避免使用`"searchs"`等关键字作为回调地址路径的一部分，回调地址<b>URL</b>需同时支持`GET`和`POST`请求；配置或更新回调地址时，尘锋SCRM会对目标回调地址发起一次`GET`请求，第三方系统需按照《三、URL配置校验（GET请求）》对请求进行正确的解密处理并返回要求内容才可以通过校验；

- **【调用数据加密**】：选择数据加密后，所有的业务数据变更事件推送时，我们将对事件body进行加密并发送POST请求到“消息与事件接受URL”，您可参考 [**解密SDK**](https://gitee.com/dustess/ww-encrypt-sdk)对其解密后使用；

- **【配置提交保存**】：点击提交按钮时，我们会向您填写的“消息与事件接受URL”发送GET请求校验URL的可用性，您需要配合[**解密SDK**](https://gitee.com/dustess/ww-encrypt-sdk)解密之后原样返回给我们，校验成功后才能配置成功。

:::caution[]
1、所配置的回调地址URL需要确保能够在公网被访问；
2、`GET`请求用于验证秘文解密逻辑是否被正确实现，SCRM系统回调该接口时，第三方系统需要对推送的秘文进行解密并返回解密后的明文，返回示例参考：`《三、URL配置校验（GET请求）- 3、三方系统-URL配置校验解密返回示例》`；
3、`POST`请求用于后续验证推送内容时是否正确被接收，接收到请求后返回指定结构体即可。返回示例参考：`《四、尘锋系统变更事件推送（POST请求）- 3、三方系统事件接收响应内容示例》`；
:::

## 三、URL配置校验（GET请求）
### 1、尘锋SCRM-URL配置校验加密请求示例
在尘锋系统配置完毕URL地址之后，尘锋系统会通过GET请求对目标地址发起加密请求；
<span style="color:red;">下列代码仅展示示例，并不能用作调试使用，请使用您公司尘锋账户的相关参数进行调试</span>
```bash
curl --location --request GET 'http://xxx.xxx.com/callbackservice/callBack?timestamp=1632380699369&echo_str=fv8w1RHUA6c+EjD8kbKLvuGt2nNz+t4wudN94kOeN8oTv61AxX7aQ2GgM9Te4j11yMU5EYryznEL1kzp/ayPyw==&msg_signature=cb300d0090f9010d3f87091e4036700d1b4b9513&nonce=qxqSWoFvucLBvOtJ'
```
### 2、三方系统-URL配置校验解密示例
三方系统接收到尘锋系统发起的GET加密请求之后，需要使用租户对应的加密信息对加密请求进行解密；

`解密所需SDK`[点击这里跳转](https://gitee.com/dustess/ww-encrypt-sdk)
```java
//消息校验Token
String token = "4ay60gxxjfLvBx4R9j5";
//消息加解密Key
String encodingAesKey = "Bc3D94xe17vYtN73PaGidS0B1Po7850h53N1QWfuPLBd";
//ClientID
String receiveId = "cfGyaexMrxKwxLcb";

BizMsgCrypt bizMsgCrypt = null;
try {
bizMsgCrypt = new BizMsgCrypt(token, encodingAesKey, receiveId);
} catch (BizException e) {
e.printStackTrace();
}
//原样返回解密后的数据
return bizMsgCrypt.VerifyURL(msgSignature, timeStamp, nonce,echo_str.replaceAll(" ","+"));
```
### 3、三方系统-URL配置校验解密返回示例
对GET请求解密后，您需要将解密后的内容原样返回给尘锋系统，如果与尘锋系统加密前的内容一致，尘锋系统将判定三方系统解密成功并且界面将成功保存，URL地址配置成功。

:::caution[]
注意：返回时Header需设置`Content-Type:text/plain`，另外切勿额外携带 "" 包装返回内容；
:::

```csharp  
B7z8vdsQYx8x61qg82
```
### 4、异常处理
报错原因为返回给尘锋的解密数据有错误，请严格根据文档说明进行解密返回。
![image.png](https://cdn-goods.dustess.com/W00000001384/goods/l/9/9/n/l99nxj0ai0c1673516601409.png)<br>

## 四、尘锋系统变更事件推送（POST请求）
URL地址配置完毕之后，当尘锋系统的客户数据有新增/删除/修改时，<span style="color:red;">尘锋会主动</span>向您填写的URL<span style="color:red;">发送POST请求</span>，携带回调数据。
### 1、尘锋推送加密请求示例
⽬前联系人事件仅会推送变更客户的id，具体事件类型由body解密后的type判断。 
`type⽀持的值：add(新增客户)/del(删除客户)/update(客户更新)。 `
三⽅拿到客户id(cus_ids)后调⽤拉取接⼝获取客户的全量信息进⾏数据同步。 
`event代表事件分类，⽬前仅⽀持customer。 `

:::warning[]
1、<span style="color:red;">加密参数通过贵司的clientId、clientToken、clientKey参与生成，以下示例仅供参考结构，不支持解密！</span>
2、删除客户的情况del_reason包括三种值：ordinaryDel（普通客户删除），userDel（员⼯删除外部联系⼈），externalDel（外部联系⼈删除员⼯）
:::

```bash
curl --location --request POST 'http://xxxxx/callBack' \
--header 'Content-Type: application/json' \
--data-raw '{
    "event": "customer",
    "body": {
        "encrypt": "ynPWUB66DfkMEXgrsSxSZQThZ8wRzvRNhcAZPvwBZXxyPIWTCltmGHB+q4Yb5lomH973gpwRKxv0sa1YLOkDdzBZy96DK64BIPlSZV7foaVGyuB/BZ4SV/eXd+B7/5iSGgH0cWeKfwq9CuCXz4ib+A7kWWpyeh98p93sQwBfPSLdEI6jQyShg4zoDItMZ73Hr3M4rKz6/WQL+pGBGk8iDw==",
        "msgSignature": "c0ff632bbd854f60b3439ce51be3e6cee44fb389",
        "timeStamp": "1636524504",
        "nonce": "dV8oWh3LvK3evzBf"
    }
}'
```
### 2、三方系统解密后完整body示例
`解密所需SDK`[点击这里跳转](https://gitee.com/dustess/ww-encrypt-sdk)
您可以根据我们传递的`type`自行规划业务逻辑
```bash
{
    "event": "customer",
    "body": {
        "type": "update",
        "cus_ids": [
            "250feed9-28ac-11ec-87fa-f285b9cf4ac7"
        ],
        "del_reason": "",
        "follow_record_ids": null
    }
}
```
### 3、三方系统事件接收响应内容示例
当您接收到我方推送的变更事件回调请求时，需返回JSON格式的code
数据类型为`int`
成功返回：1
失败返回：0 
```json
{
"code" : 1
}
```
:::caution[]
<br>
<span style="text-align:left;color:red;"><b>1、回调服务需在3秒内完成响应，建议收到消息推送后⽴刻返回成功响应示例，避免⼀直占⽤请求连接，被判超时<br>
2、切勿在回调处理逻辑内增加额外业务处理逻辑，避免延长响应时间，当推送事件较频繁时，可能会导致接口请求超时。</b></span><br>
3、推送限制：多次响应超时、服务器⽆响应、多次响应失败，10分钟内达到100次，推送接⼝将降低所有推送事件频率为3⼩时⼀次。

:::

## 五、加密SDK（自测）
尘锋通过`BizMsgCrypt.EncryptMsg(String replyMst)`将数据加密并推送给您，您也可以通过此函数自行校验；
**加密所需参数以您在尘锋系统里获取到的为准。**

![WX20241230-191459@2x.png](https://api.apifox.com/api/v1/projects/4227827/resources/487179/image-preview)
![image.png](https://cdn-goods.dustess.com/W00000001384/goods/k/3/8/9/k389ghbx9b1673516608939.png)<br>


## 六、三方系统-接口处理代码示例

```java
/*
java 定义一个支持GET+POST请求的controller，用于GET校验+POST回调事件接收，仅为参考示例。
*/
@RequestMapping(value = "/callback")
    public Object callBack(
            @RequestParam(value = "echo_str",required = false) String encrypt,
            @RequestParam(value = "msg_signature",required = false) String msgSignature,
            @RequestParam(value = "timestamp",required = false) String timeStamp,
            @RequestParam(value = "nonce",required = false) String nonce,
            @RequestBody(required = false) SyncContactCallBackParam syncContactCallBackParam,
            HttpServletRequest request,
            HttpServletResponse response) {
            BizMsgCrypt bizMsgCrypt = null;
        try {
            bizMsgCrypt = new BizMsgCrypt(token, encodingAesKey, receiveId);
        } catch (BizException e) {
            e.printStackTrace();
        }
        //GET校验解密逻辑
       return bizMsgCrypt.VerifyURL(msgSignature, timeStamp, nonce, encrypt.replaceAll(" ", "+"));
            }

```

### Q1：处理GET请求时为什么要将" "全量替换为"+"?
url传输过程中会将"+"替换为空格，导致解密失败，您可以使用此函数进行处理
```java
public String replaceAll(String regex, String replacement) {
        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
    }
```
![image.png](https://cdn-goods.dustess.com/W00000001384/goods/3/2/f/u/32furzbgeu41673516612024.png)<br>
### Q2：java.security.InvalidKeyException: Illegal key size
`解决方案`[JCE无限制权限策略文件](https://blog.csdn.net/dling8/article/details/84061948)

### Q3：commons-codec依赖
当解密遇到以下报错时可以尝试添加此版本依赖解决
Exception in thread "main" java.lang.IllegalArgumentException: Last encoded character (before the paddings if any) is a valid base 64 alphabet but not a possible value
```xml
<dependency>
       <groupId>commons-codec</groupId>
       <artifactId>commons-codec</artifactId>
       <version>1.15</version>
</dependency>
```
