- 最新动态
- 产品介绍
- 快速入门
-
用户指南
- 云控制台操作指南
-
租户管理员指南
- 认识您的租间
- 配置员工中心
- 启用人工服务
- 配置移动客服
- 配置多媒体渠道
-
机器人管理配置指南
- 快速入门
-
配置智能机器人
- 概述
- 配置一个预约挂号机器人(任务型对话机器人)
- 添加问答型对话机器人
- 其他操作
-
相关参考
- 图元
- 参数
-
TUC接口
- /chatbot/rest/tuc/v1/nlp/detectRegularEntity
- /chatbot/rest/tuc/v1/nlp/identify
- /chatbot/rest/tuc/v1/recommendFaq
- /chatbot/rest/tuc/v1/qualityInspection/qiOnline/recognize
- /chatbot/rest/tuc/v1/nlp/feedback
- /chatbot/rest/tuc/v1/nlp/textClassify
- /chatbot/rest/tuc/v1/nlp/detectEntity
- /chatbot/rest/tuc/v1/qualityInspection
- 内置函数
- 常见问题
- 操作员:配置普通IVR
- 配置预置流程
- IVR Journey分析
- 外呼风险监控
- 管理工单配置
- 质检管理
- 管理通知中心
- 管理客户中心
- 配置智能外呼
- 管理问卷
- 管理智能实训
- 配置知识库
- 配置公共资源
- 业务故障放通管理
- 护航浏览
- 社交媒体运营
- 绩效管理
- 客服座席指南
- 质检员指南
- 价格说明
-
开发指南
- 开发概述
- 用户接入——VOIP音视频接入
- 用户接入——网页版客户端集成 (RESTful)
- 用户接入——网页版轻量级客户端集成 (JS)
- 座席集成——座席轻量级接续块集成(JS)
- 座席集成——座席呼叫处理 (RESTful)
-
座席集成——Openeye H5 软电话接口集成
- 修订记录
- OpenEye H5软电话接口概述
- OpenEye软电话安装指导
- 座席侧集成H5软电话开发指导
- 音频呼叫接口
-
音视频呼叫接口扩展
- 音视频呼叫
-
设备管理
- getMediaDevices(获取设备列表)
- setMicIndex(设置麦克风)
- mediaGetMicIndex(查询当前使用的麦克风)
- setSpeakIndex (设置扬声器)
- mediaGetSpeakIndex (查询当前使用的扬声器)
- setMicVol(设置麦克风音量)
- getMicVol(查询麦克风当前音量)
- setSpkVol(设置扬声器音量)
- getSpkVol(查询扬声器当前音量)
- setVideoWindowParam(设置视频窗口位置和宽高)
- setVideoLayoutMode(设置视频窗口画面排列模式)
- setVideoDisplayMode(设置视频窗口画面裁剪模式)
- openCamera(打开摄像头)
- closeCamera(关闭摄像头)
- 屏幕共享
- 截屏
- 录屏
- 错误码列表
- 运营管理——座席工作台集成第三方Web页面
-
API参考
- 接口概述
- 相关术语
- 修改记录
- 接口鉴权方式
-
呼叫中心配置类
-
座席管理
- 单个创建座席业务账号(agentAccount/create)
- 单个删除指定座席业务账号(agentAccount/delete)
- 单个修改座席业务账号信息(agentAccount/update)
- 查询座席业务账号信息(agentAccount/query)
- 绑定座席和技能队列(addSkillsToAgent)
- 解绑座席某技能队列(releaseAgentBySkillId)
- 通过技能队列ID查询座席信息(queryAgentInfoBySkillId)
- 修改座席软电话号码登录密码(updateSipPhonePassword)
- 查询所有座席的软电话信息 (不包含业务账号) (querySysInfo)
- 查询所有座席的软电话信息 (包含业务账号) (queryAgentInfo)
- 查询账号登录结果 (queryAgentLoginParams)
- 根据登录账号查询座席信息 (queryAgentInfoByAccount)
- 按客户号码清理数据 (cleancustpersonaldata)
- 技能队列管理
- 号码管理
- IVR流程管理
-
座席管理
-
座席工作台
- 座席控制
-
座席双呼
- 创建双呼呼叫 (V1.0.0) (createCall)
- 创建双呼呼叫 (V3.0.0) (createCall)
- 查询呼叫历史记录 (queryCallDetailRecord)
- 查询呼叫状态 (queryCallState)
- 获取录音文件地址 (getRecordingAddress)
- 查询分配的软电话号码 (V1.0.0) (queryPhone)
- 查询分配的软电话号码 (V2.0.0) (queryPhone)
- 获取呼叫目的设备信息 (getCalledInfo)
- 创建语音外呼(V1.0.0)(createVoiceNotification)
- 创建语音外呼(V2.0.0)(createVoiceNotification)
- 查询当前会话客户的最近历史接触记录(queryUserContactLimit)
- 查询通话信息(queryCallInfoByCallId)
- ITA双呼结果通知(statusnotify)
- 回调接口
- 订阅语音识别结果接口
- App个人设置
- 附录
- 电销外呼
- 调查问卷
- 知识库管理
- 机器人管理
-
网页客户端接入
- 接口调用流程
- 第三方请求鉴权 (applyToken)
- 查询排队信息 (queryQueueInfo)
- 主动轮询座席侧发送的信息 (poll)
- 保存客户提交的满意度评价结果 (saveSatisfaction)
- 发送消息 (send)
- 客户发送文件 (uploadFileStream)
- 客户接收文件 (downloadFileStream)
- 根据客户输入联想常用语 (queryPhraseByKeyword)
- 检查当前租间是否支持点击通话 (checkClickToCallSupport)
- 创建点击通话 (createClickToCall)
- 获取点击通话事件 (getClickToCallEvents)
- 释放点击通话 (dropClickToCall)
- 创建匿名通话 (createcall)
- 客户提交留言 (doLeaveMessage)
- 提交客户对机器人满意度评价结果 (feedbacksatisfaction)
- 查询历史消息 (queryHistoryChatMessage)
- 丢弃邮件(chat_dropMail)
- 提供whatsapp发送下行消息(sendWhatsappMessage)
- 查询在线交谈工作台当前交谈的消息(getUserInfoBycallId)
- 查询满意度调查配置(getSatisfactionSurveyMode)
-
质检/监控/统计类
- 实时质检:qualitycontrol
-
智能质检
- 质检评分接口 (scoresetting)
- 句子管理接口 (sentencemanagement)
- 敏感词管理接口 (sensitiveWordManage)
- 话术接口 (conversationspecific)
- 句子、敏感词训练接口 (SemanticKeywordTraining)
- 对话逻辑接口 (conversationflow)
- 对话规则接口 (conversationrules)
- 抢插话规则接口 (interposalrules)
- 静默规则接口 (silencerule)
- 语速规则接口 (speedrule)
- 质检场景管理接口 (scenariomanage)
- 通话质检接口 (qualitycheckmanage)
- 人工抽检任务接口 (regularQualityTask)
- 质检任务接口 (qualitytask)
- 质检任务详情接口 (qualitytaskdetail)
- 质检申诉接口 (qualityitem)
- 第三方录音质检接口 (asrtrans)
-
监控/统计
-
实时数据查询类接口
-
VDN维度实时接口
- 查询指定VDN下的系统接入码信息
- 查询指定VDN下的座席休息情况
- 查询指定VDN下的座席电话号码
- 查询指定VDN下的所有座席信息
- 查询指定VDN下的所有座席的当前状态信息
- 查询指定VDN下的所有座席的静态配置信息
- 查询指定VDN下的IVR详细状态信息
- 查询指定VDN下的IVR流程接入码信息
- 查询指定VDN下的各技能队列相关信息
- 查询指定VDN所有休息原因码
- 查询指定接入码编号的呼叫信息
- 查询指定VDN下的呼叫信息
- 查询指定VDN下的呼叫信息(v2)
- 查询指定VDN下的通话轨迹数据
- 查询指定VDN下的所有座席的静态配置信息(CTI3.6版本不支持)
- 查询指定VDN下的所有座席信息(CTI3.6版本不支持)
- 获取VDN实时监控指标
- 技能队列维度实时接口
- 座席维度实时接口
- 呼叫明细维度实时接口
-
VDN维度实时接口
- 历史数据查询类接口
- 配置数据查询类接口
- 质检关系维护接口
- 外呼任务列表查询接口
- 系统指标查询接口
- 健康检查接口
- 附录
-
实时数据查询类接口
- 录音/话单类
- 语音通知
- OMA接口参考
- Case2.0接口参考
- DataProcess接口参考
- 其他类接口参考
- 常见问题
- 文档下载
- 通用参考
展开导读
链接复制成功!
开发Authorization签名生成机制
您需要开发一个生成Authorization签名的认证机制,云客服需要用您生成的authorization签名来进行鉴权。
在开发前,请您先了解生成Authorization签名的内部规则,如图1所示。
了解完以上原理与规则后,请您依据以下步骤进行Authorization签名认证机制的开发:
- 生成SignedHeaders:遍历参与编码的HttpHead里面的Header name。
- 将Header name都改为小写,即调用lowerCase()函数,SignerUtils工具类请参考1,参考如下:
private Map<String, String> lowerCaseSignedHeaders(Map<String, String> signedHeaders) { if ((null == signedHeaders) || signedHeaders.isEmpty()) { throw new IllegalArgumentException("signedHeaders cann't be null."); } Map<String, String> headers = new HashMap<>(SignerUtils.HASH_MAP_INITIALIZATION_SIZE); for (Map.Entry<String, String> e : signedHeaders.entrySet()) { String name = e.getKey(); String value = e.getValue(); headers.put(name.toLowerCase(Locale.ENGLISH), value.trim()); } return headers; }
- 将步骤1-1中Header name转换后的字符后面追加分割符";",生成一条记录,注意最后一个字段不追加";"。
- 将步骤1-1中所有记录按照字典排序,然后按照顺序连接成一个大字符串,参考如下。
private String appendSignedHeaders(StringBuilder buffer) { int start = buffer.length(); Set<String> headerNames = new TreeSet<>(this.signedHeaders.keySet()); for (String name : headerNames) { buffer.append(name).append(';'); } buffer.deleteCharAt(buffer.length() - 1); int end = buffer.length(); String signedHeadersStr = buffer.substring(start, end); return signedHeadersStr; }
说明:
请对以下Header进行编码:
Content-Length="***"
Content-Type="application/json;charset=UTF-8"
- 将Header name都改为小写,即调用lowerCase()函数,SignerUtils工具类请参考1,参考如下:
- 生成authStringPrefix。
将以下字段用“/”进行拼接authVersion、accessKey、timestamp、SignedHeaders。格式如下:
authStringPrefix="auth-v2/{accessKey}/{timestamp}/{SignedHeaders}";
说明:
- auth-v2:鉴权版本号,当期版本为固定字符串“auth-v2”。
- accessKey:第三方系统使用configId(渠道ID)作为唯一标识。
- timestamp:取第三方发起服务时的时间,timestamp为String类型。时间字符串格式化为"yyyy-MM-dd'T'HH:mm:ss.SSS'Z"。
- SignedHeaders:参与编码的HttpHead里面的Header name,由步骤1生成。
- 生成signingKey。
将步骤2生成的authStringPrefix按照sha256Hex进行加密,其中密钥SecretKey为第三方系统在渠道配置页面配置的密钥。sha256Hex算法参考如下,SignerUtils工具类请参考1:
public static String sha256Hex(String key, String toSigned) throws NoSuchAlgorithmException,InvalidKeyException, UnsupportedEncodingException { Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(key.getBytes(SignerUtils.CHARSET), "HmacSHA256")); String digit = new String(SignerUtils.encodeHex(mac.doFinal(toSigned.getBytes(SignerUtils.CHARSET)))); return digit; }
- 生成CanonicalHeaders。
说明:
要求计算的编码规则与SignedHeaders一致,但增加了head value的编码。
- 遍历参与编码的HttpHead里面的head name,将Header name都改为小写,即调用lowerCase()函数(请参考步骤1)。
- 调用normalize函数,对刚才转换后的小写字符串进行格式化,PathUtils工具类请参考2。
/** * normalize * @param value payload信息 * @return builder */ public static String normalize(String value) { try { StringBuilder builder = new StringBuilder(PathUtils.DEFAULT_CAPACIT); for (byte b : value.getBytes(PathUtils.CHARSET)) { if (PathUtils.URI_UNRESERVED_CHARACTERS.get(b & 0xFF)) { builder.append((char) b); } else { builder.append(PathUtils.PERCENT_ENCODED_STRINGS[b & 0xFF]); } } return builder.toString(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } }
- 将步骤4-1中的记录按照字典排序,进行排序。
- 遍历排序后的记录,中间追加字符串"\n"连接成一个大的字符串,最后一条记录不追加"\n"。
- 生成canonicalRequest。
将字段“HttpMethod”、“HttpURI”、“SignedHeaders”、“CanonicalHeaders”、“NormalizePath”用“\n”拼接,最后一条记录不追加"\n",PathUtils工具类请参考2。。
private String canonicalRequest() { StringBuilder buffer = new StringBuilder(PathUtils.DEFAULT_CAPACITY); buffer.append(this.httpMethod).append(System.lineSeparator()); buffer.append(this.uri).append(System.lineSeparator()); this.appendSignedHeaders(buffer); buffer.append(System.lineSeparator()); this.appendCanonicalHeaders(buffer); buffer.append(System.lineSeparator()); if (this.isNotEmpty(this.payload)) { buffer.append(PathUtils.normalize(this.payload)); } return buffer.toString(); }
格式参考如下:
CanonicalRequest = $HttpMethod + "\n" + $HttpURI+ "\n" + SignedHeaders($HttpHeaders) + "\n" + CanonicalHeaders ($HttpHeaders) + "\n" + NormalizePath($HttpBody)
说明:
- CanonicalRequest参数说明:
$HttpMethod:指HTTPS协议中定义的GET、PUT、POST等请求,必须使用全大写的形式。
$HttpURI:指接口请求的URI,必须以“/”开头,不以“/”开头的需要补充上,空路径为“/”,样例:/service-cloud/webclient/chat_client/js/newThirdPartyClient.js。
SignedHeaders:步骤1生成的SignedHeaders。
CanonicalHeaders:步骤4生成的CanonicalHeaders。
NormalizePath:格式化处理后的Body体。
- 仅对NormalizePath中的如下参数进行编码:
thirdUserId:企业用户ID。
tenantSpaceId:企业系统提供的租间ID。
channelConfigId:企业接入的渠道ID。
- CanonicalRequest参数说明:
- 生成signature。将步骤5生成的canonicalRequest再按照sha256Hex进行加密,此处加密的密钥key为步骤3生成的signingKey。
- 生成签名authorization:将步骤2生成的authStringPrefix和步骤6生成的signature用“/”进行拼接。格式参考如下:
Authorization:$authStringPrefix/$Signature
相关参考
生成Authorization签名的认证机制过程中,涉及到SignerUtils与PathUtils工具类,格式参考如下:
- SignerUtils
import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Locale; import java.util.Map; public class SignerUtils { private static final int HASH_MAP_INITIALIZATION_SIZE = 5; private static final int ONE_CHAR_BITS_NUM = 4; private static final String CHARSET = "UTF-8"; private static final char[] DIGITS_LOWERS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; private SignerUtils() { } private static char[] encodeHex(final byte[] data) { final int le = data.length; final char[] outs = new char[le << 1]; for (int i = 0, j = 0; i < le; i++) { outs[j++] = SignerUtils.DIGITS_LOWERS[(0xF0 & data[i]) >>> ONE_CHAR_BITS_NUM]; outs[j++] = SignerUtils.DIGITS_LOWERS[0x0F & data[i]]; } return outs; } }
- PathUtils
import java.io.UnsupportedEncodingException; import java.util.BitSet; import java.util.Locale; import java.util.concurrent.CompletionException; public class PathUtils { private static final String CHARSET = "UTF-8"; private static final int NUM_256 = 256; private static final int DEFAULT_CAPACITY = 16; private static final BitSet URI_UNRESERVED_CHARACTERS = new BitSet(); private static final String[] PERCENT_ENCODED_STRINGS = new String[NUM_256]; static { for (int i = 97; i <= 122; i++) { PathUtils.URI_UNRESERVED_CHARACTERS.set(i); } for (int i = 65; i <= 90; i++) { PathUtils.URI_UNRESERVED_CHARACTERS.set(i); } for (int i = 48; i <= 57; i++) { PathUtils.URI_UNRESERVED_CHARACTERS.set(i); } PathUtils.URI_UNRESERVED_CHARACTERS.set(45); PathUtils.URI_UNRESERVED_CHARACTERS.set(46); PathUtils.URI_UNRESERVED_CHARACTERS.set(95); PathUtils.URI_UNRESERVED_CHARACTERS.set(126); for (int i = 0; i < PathUtils.PERCENT_ENCODED_STRINGS.length; i++) { PathUtils.PERCENT_ENCODED_STRINGS[i] = String.format(Locale.ROOT, "%%%02X", new Object[]{Integer.valueOf(i)}); } } private PathUtils() {} }