新建鉴权方式
操作路径:管理-第三方对接-API概览与设置-新增
选择对应加签算法,填写好SecretValue,SecretValue将会作为密钥对实际http请求进行加签;
IVR配置调用API节点
操作路径:管理-IVR管理-新增(编辑)- 新增节点“调用API”
选择已配置的鉴权方式,填写好对应API Request信息;(记得填写适当的最大请求超时时间)
根据响应数据来分流到不同逻辑
转坐席组:记得先将测试人员账号添加到坐席组(操作路径: 管理-坐席组管理- 编辑成员)
线路路由关联IVR流程
操作路径:管理 - 呼叫中心设置 - 路由管理 - (已有路由)编辑
呼入触发流程
从外部呼入到线路上已绑定的号码
附:服务端加签验证工具
package com.nx.callcenter.service.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSONObject;
import com.nx.callcenter.enums.TenantApiAuthEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
/**
* @author huangqueqi
*/
@Slf4j
public class ApiAuthSignUtils {
/**
* 生成接口参数签名demo
*/
public static void main(String[] args) {
// header参数
Map<String, String> headers = new HashMap<>(8);
headers.put("secretKey", "77ed1dda");
headers.put("action", "test");
headers.put("timestamp", System.currentTimeMillis()/1000 + "");
// accessKey对应的密码
String accessSecret = "00163e067561";
// 业务参数
Map<String, Object> body = new HashMap<>();
body.put("id", 10001);
body.put("name", "牛小信");
System.out.println(calcSign(headers, body, accessSecret,"HMAC-MD5"));
// System.out.println(calcSign(headers, body, accessSecret,"HMAC-SHA256"));
// System.out.println(calcSign(headers, body, accessSecret,"HMAC-SHA512"));
// log.info("sign: {}", sign); // sign: 87c3560d3331ae23f1021e2025722354
}
/**
* 计算sign签名
*
* @param headers 请求头中的公共参数
* @param body body中的json字符串
* @param accessSecret 秘钥
* @param algorithmType 加密方式
* @return
*/
public static String calcSign(Map<String, String> headers, Map<String, Object> body,
String accessSecret, String algorithmType) {
try{
StringBuilder raw = new StringBuilder();
// step1: 拼接header参数
if(CollUtil.isNotEmpty(headers)) {
// 使用TreeMap自动按ASCII码升序排序
Map<String, String> sortedHeaders = new TreeMap<>(headers);
for (Map.Entry<String, String> entry : sortedHeaders.entrySet()) {
raw.append(entry.getKey())
.append("=")
.append(entry.getValue())
.append("&");
}
if (raw.length() > 0) {
raw.deleteCharAt(raw.length() - 1); // 删除末尾多余的&
}
log.info("step1: {}", raw); // step1: action=test&secretKey=77ed1dda×tamp=1743413535
}
// step2: 拼接body参数
if(CollUtil.isNotEmpty(body)) {
String bodyStr = JSONObject.toJSONString(body);
if (raw.length() > 0) {
raw.append("&body=").append(bodyStr); // action=test&secretKey=77ed1dda×tamp=1743413535&body={"name":"牛小信","id":10001}
}else{
raw.append(bodyStr); // {"name":"牛小信","id":10001}
}
log.info("step2: {}", raw); // action=test&secretKey=77ed1dda×tamp=1743413535&body={"name":"牛小信","id":10001}
}
// step3: 拼接accessSecret
raw.append("&accessSecret=").append(accessSecret);
log.info("step3: {}", raw); // test&secretKey=77ed1dda×tamp=1743413535&body={"name":"牛小信","id":10001}&accessSecret=00163e067561
// step4: MD5算法加密,结果转换成十六进制小写
String sign = null;
if(algorithmType.equals(TenantApiAuthEnum.ALGORITHM_MD5.getName())) {
sign = DigestUtils.md5Hex(raw.toString());
}else if(algorithmType.equals(TenantApiAuthEnum.ALGORITHM_SHA256.getName())) {
sign = DigestUtils.sha256Hex(raw.toString());
}else if(algorithmType.equals(TenantApiAuthEnum.ALGORITHM_SHA512.getName())) {
sign = DigestUtils.sha512Hex(raw.toString());
}
log.info("step4: algorithmType={}, sign={}", algorithmType, sign); // step4: sign=fe78d3b72cef9247e7e14add91019397
return sign;
}catch (Exception e){
log.error("ApiAuthSignUtils.calcSign error",e);
}
return null;
}
}