1.认证授权回调通知概述
- 首先,开发者配置回调通知Web Url地址。
- 每当,认证和授权相关事件发生时(如完成实名认证),系统通知服务将会创建一个JSON对象,其中包含事件类型和与该事件相关的数据等信息。
- 然后,系统通知服务通过 HTTP POST 请求将JSON对象发送到开发者配置的回调通知 Web Url中。
- 开发者业务系统在收到回调通知后,可根据事件类型和相关数据做下一步的业务处理。
- 若开发者业务系统所在网络有安全策略限制,请查阅附3 系统回调通知服务器信息进行防火墙配置。
2.接收认证和授权类回调通知
2.1 准备一个支持 HTTP POST 的 Web 服务
系统通知服务将以 HTTP POST 方式推送 JSON 格式的数据,因此开发者所提供的 Web 服务需要能够接收并解析来自HTTP POST 请求的 JSON 数据并能够返回相应 HTTP 状态码。
2.2 设置回调通知Url地址
【注意事项】
- 回调通知Url地址格式需符合 {scheme}://{host}:{port}/{path},详见文末附2 回调通知URL格式说明。
- 请确保回调通知Url地址拼接正确,且互联网可成功访问。
如果以下两种设置回调通知方式均设置,均会触发回调通知(地址相同就触发两次)
方式一:接口设置
开发者可通过【获取个人认证&授权页面链接】或【获取机构认证&授权页面链接】接口中的notifyUrl
请求参数来配置认证和授权类回调通知Url地址。(接口设置不包含授权范围变更通知)
方式二:请开发者提供回调通知URL地址,供后端配置。
2.3 接收并响应
2.3.1 接收系统回调通知
当某个事件发生后,系统会主动 POST 请求开发者所设置的回调通知 Url 地址,并推送对应的事件数据信息。
例如:当完成实名认证或授权操作后,系统将推送实名认证通过事件数据信息。
【提示】
- 若贵司有网络安全策略,请按照文末附3 系统通知服务器信息配置防火墙,以便成功接收回调通知。
- 若开发者长时间未收到系统的回调通知,可主动调用相关查询接口,以便获知签署流程当前进展状态。
请求头数据格式如下:
{ | |
"X-Tsign-Open-TIMESTAMP":"1713508339505", | |
"X-Tsign-Open-SIGNATURE-ALGORITHM":"hmac-sha256", | |
"X-Tsign-Open-App-Id":"74XXXXXX", | |
"X-Tsign-Open-SIGNATURE":"60c6719d332420f251234d72631e93e83e80061f47f78bc483a851a710" | |
} |
请求Body数据格式如下:
{ | |
"action":"AUTH_PASS", | |
"authFlowId":"RN-***5080050", | |
"timestamp":1650362853970, | |
"authType":"PSN", | |
"psnInfo":{ | |
"psnId":"ed8c1b146c3aa***0a8f6", | |
"psnAccount":{ | |
"accountMobile":"183****0101", | |
"accountEmail":"" | |
} | |
} | |
} |
其中:
action 为业务事件类型,开发者可以通过判断返回 JSON 中的 action 业务事件类型,来进行下一步业务处理。
可通过查看文末附1 Action事件列表了解签署类相关事件的回调通知数据。
Action事件类型可能会出现新增,建议开发者考虑兼容性处理,防止出现代码异常造成业务卡死。
例如,Action业务事件类型判断时,仅将贵司业务需要的类型进行判断并进入下一步业务,其他不需要的类型做忽略处理,这样可以防止新增类型对现有业务造成影响。
2.3.2 响应系统回调通知
系统的回调通知触发后,返回的200 ~ 299之间的 HTTP 状态码均会被系统通知服务认定为通知成功。
除返回 HTTP 状态码之外,同时建议开发者按以下 JSON 格式向系统通知服务返回 Body体数据(系统不对开发者返回的Body体数据做判断)。
{"code":"200","msg":"success"} |
【注意事项】
- 返回给系统的 HTTP 状态码介于200~299之间,系统认为通知成功,否则系统认为通知失败。
- 通知失败后,系统通知服务将会进行最多16次重试通知。重试机制如下:
(若中间重试通知成功,则中断不再继续重试)

- 为避免因系统通知服务解析 JSON 数据失败而导致重复通知,请确保返回的 JSON 数据中不含空格 \/等特殊字符,建议接收成功时直接返回
{"code":"200","msg":"success"}
。 - 为了保障回调通知的时效性和可靠性,建议开发者在接收到回调通知后在5秒内返回 HTTP 状态码(200)给系统通知服务。
- 若开发者无法在5秒内完成回调通知相关业务处理,请采用异步方式进行后续业务处理。
3.系统回调通知安全机制
为了保证回调通知数据推送的安全,系统提供IP白名单模式和签名验签模式两种模式供开发者选择。
两种模式可以单独使用,也可以组合使用。
3.1 IP白名单模式
开发者可以采用IP白名单机制来保障回调通知接收服务的安全,开发者可以参考文末附3 系统通知服务器信息来配置贵司的防火墙。
以下以Nginx服务器为例,介绍如何配置防火墙白名单来允许系统回调通知服务入站。
(1)新建白名单文件 ip_white.conf
新建文件ip_white.conf,内容如下:
allow 120.25.168.36; | |
allow 120.25.168.36; |
(2)nginx.conf 配置示例
#geoIP的白名单设置 | |
geo $remote_addr $ip_whitelist { | |
default 0; | |
include ip_white.conf; | |
} | |
location /console { | |
proxy_redirect off; | |
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | |
proxy_set_header X-Real-IP $remote_addr; | |
proxy_set_header Host $http_host; | |
if ( $ip_whitelist = 1 ) { | |
proxy_pass http://127.0.0.1:8000; | |
break; | |
} | |
return 403; | |
} |
(3)Java中获取请求IP代码示例
public static String getClientIp(HttpServletRequest request) { | |
String ip = request.getHeader("x-forwarded-for"); | |
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) { | |
// 多次反向代理后会有多个ip值,第一个ip才是真实ip | |
if( ip.indexOf(",")!=-1 ){ | |
ip = ip.split(",")[0]; | |
} | |
} | |
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
ip = request.getHeader("Proxy-Client-IP"); | |
} | |
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
ip = request.getHeader("WL-Proxy-Client-IP"); | |
} | |
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
ip = request.getHeader("HTTP_CLIENT_IP"); | |
} | |
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
ip = request.getHeader("HTTP_X_FORWARDED_FOR"); | |
} | |
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
ip = request.getHeader("X-Real-IP"); | |
} | |
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { | |
ip = request.getRemoteAddr(); | |
} | |
return ip; | |
} |
3.2 签名验签模式
开发者在接收到回调通知时,可以借助请求头 Header 中的信息对推送的数据进行签名验签。
请求头 Header 参数如下:
参数名称 | 参数类型 | 参数说明 |
X-Tsign-Open-App-Id | header | 客户发生业务时的项目ID |
X-Tsign-Open-SIGNATURE | header | 签名值 |
X-Tsign-Open-TIMESTAMP | header | 时间戳 |
X-Tsign-Open-SIGNATURE-ALGORITHM | header | 使用的算法, 默认算法 hmac-sha256 |
以算法hmac-sha256签名验证做说明,验签的数据有四部分
- 1、时间戳
回调header的X-Tsign-Open-TIMESTAMP
- 2、query请求的数据
开发者设置的回调地址可能包含query数据,例如callback?accountId=aaa&orderNo=001,多个 Query 参数需要对 key 按字典(ASCII码)升序排序后,再按照value1+value2方法拼接。(本系统接口不会追加任何参数)
- 3、body 数据
即通知实际内容,按照整体的字节流来处理
- 4、应用secret
由平台向开发者提供secret,请联系账户专员或在线支持。
JAVA代码示例
【点击下载回调通知签名验签JAVA_Demo:XYAPINotifySafe.zip】
PHP代码示例
| |
callback(); | |
//签署回调 | |
function callback(){ | |
// 此处可以打印下日志 | |
$file = fopen('callback.log', "a"); | |
fwrite($file, "startTime".date('Y-m-d H:i:s')); | |
if($_SERVER['REQUEST_METHOD'] != 'POST'){ | |
fwrite($file,'非法回调');exit; | |
} | |
fwrite($file, json_encode($_SERVER)); | |
// 校验签名 如果header里放入的值为X_TSIGN_OPEN_SIGNATURE,到header里会自动加上HTTP_,并且转化为大写,取值时如下 | |
if(!isset($_SERVER['HTTP_X_TSIGN_OPEN_SIGNATURE'])){ | |
echo "签名不能为空";exit; | |
} | |
$sign = $_SERVER['HTTP_X_TSIGN_OPEN_SIGNATURE']; | |
fwrite($file,'sign:'.$sign); | |
$secret = 'xxxxx';//应用对应密钥 | |
//1.获取时间戳的字节流 | |
if(!isset($_SERVER['HTTP_X_TSIGN_OPEN_TIMESTAMP'])){ | |
echo "时间戳不能为空";exit; | |
} | |
$timeStamp = $_SERVER['HTTP_X_TSIGN_OPEN_TIMESTAMP']; | |
//2.获取query请求的字节流,对 Query 参数按照字典对 Key 进行排序后,按照value1+value2方法拼接 | |
$params = $_GET; | |
if(!empty($params)){ | |
ksort($params); | |
} | |
$requestQuery = ''; | |
foreach($params as $val){ | |
$requestQuery .= $val; | |
} | |
fwrite($file,'获取query的数据:'.$requestQuery); | |
//3. 获取body的数据 | |
$body = file_get_contents("php://input"); | |
fwrite($file,'获取body的数据:'.$body); | |
//4.组装数据并计算签名 | |
$data = $timeStamp . $requestQuery . $body; | |
fwrite($file,'组装数据并计算签名:'.$data); | |
echo $sign; | |
$mySign = hash_hmac("sha256", $data, $secret); | |
echo $mySign; | |
if($mySign != $sign){ | |
echo '验签失败'; | |
fwrite($file,"签名校验失败"); | |
}else{ | |
echo '验签成功'; | |
} | |
$result = json_decode($body,true); | |
switch ($result['action']){ | |
case 'SIGN_MISSON_COMPLETE': | |
//签署人签署完成回调 | |
break; | |
case 'SIGN_FLOW_COMPLETE': | |
//流程结束逻辑处理 | |
break; | |
} | |
} |
.NET代码示例
public static void notify() | |
{ | |
//异步通知获取到的header头中的签名值:X-Tsign-Open-SIGNATURE | |
string signture = "4009ffb1c50d3c12c977b8XXXXXXX0605aaf5dc55dce1d4fc1c1f39c958"; | |
//异步通知获取到的header头中的时间戳:X-Tsign-Open-TIMESTAMP | |
string timeStamp = "1703756522169"; | |
//案例:异步通知请求地址 "notifyUrl": "http://demo.tsign.cn/notify?orderNo=001&belong=pinjie", | |
//案例:"pinjie"和"001"是开发者异步地址上拼接的Query参数值,多个Query参数需要对 key 按字典(ASCII码)升序排序后,再按照value1+value2方法拼接 | |
//如果异步通知地址没有拼接Query,那么这里不需要参与签名计算 | |
string query = "pinjie001"; | |
//应用secret | |
string secret = "xxxx4d8f922b898ac519b4cf"; | |
//异步通知获取到的body体请求参数 | |
string bodyData = "{\"action\":\"SIGN_MISSON_COMPLETE\",\"timestamp\":1703756522164,\"signFlowId\":\"5ed6b3******dcdeddc23ebf\",\"customBizNum\":\"自定义编码001\",\"signOrder\":1,\"operateTime\":1703756521000,\"signResult\":2,\"resultDescription\":\"签署完成\",\"organization\":{\"orgId\":\"842ec8c******91662f\",\"orgName\":\"测试有限公司\"}}"; | |
//最终参与验签的请求参数 | |
string data = timeStamp + query + bodyData; | |
//计算签名方法 | |
string MYSIGN = GetSignature(data, secret); | |
string mysign = MYSIGN.ToLower(); | |
Console.Write("mysign=" + mysign); | |
if (mysign.Equals(signture)) | |
{ | |
MessageBox.Show("验签成功"); | |
} | |
else | |
{ | |
MessageBox.Show("验签失败"); | |
} | |
} | |
public static string GetSignature(string data, string secret) | |
{ | |
byte[] keyByte = Encoding.UTF8.GetBytes(secret); | |
byte[] messageBytes = Encoding.UTF8.GetBytes(data); | |
using (var hmacsha256 = new HMACSHA256(keyByte)) | |
{ | |
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes); | |
StringBuilder sb = new StringBuilder(); | |
foreach (byte test in hashmessage) | |
{ | |
sb.Append(test.ToString("X2")); | |
} | |
return sb.ToString(); | |
} | |
} |
附1 Action事件列表
开发者可通过判断系统通知服务推送的 JSON 中的 Action 事业类型,从而进行下一步业务处理。
Action事件类型可能会出现新增,建议开发者考虑兼容性处理,防止出现代码异常造成业务卡死。
例如,Action业务事件类型判断时,仅将贵司业务需要的类型进行判断并进入下一步业务,其他不需要的类型做忽略处理,这样可以防止新增类型对现有业务造成影响。
Action 事件类型 | Action 对应事件名称 |
认证授权类通知事件 | |
AUTH_PASS | |
AUTHORIZE_FINISH | |
AUTHORIZE_CHANGE |
附2 回调通知URL格式说明
URL格式:{scheme}://{host}:{port}/{path}
【解释说明】
scheme
指 https 或 http 协议
host
指 贵司用来接收回调通知的域名或公网IP
port
指 贵司用来接收回调通知的Web服务端口
path
指 贵司用来接收回调通知的Web服务具体路径(允许含带Query参数,如path?type=xxx)
注:回调通知Url中不能含有空格或其他特殊字符。
正确示例 | |
正确的URL格式: | https://example.demo.cn:8080/notify/receive |
正确的URL格式: | http://223.X.X.5:8080/notify/receive |
错误示例 | |
只有路径没有地址: | .notify/receive |
只有地址,没有具体服务路径: | https://example.demo.cn:8080 |
本地内网IP,互联网无法访问: | https://localhost:8080/notify/receive |
本地内网IP,互联网无法访问: | http://192.168.1.1:8080/notify/receive |
本地内网IP,互联网无法访问: | https://127.0.0.1:8080/notify/receive |
非URL格式: | test、123456等 |
附3 系统回调通知服务器信息
如果贵司需要防火墙配置后才允许系统消息通知服务推送数据,请根据下方信息进行贵司防火墙设置。
从开发者角度,以下信息需配置到开发者防火墙的入站规则中。
用途 | 环境 | 域名 | 公网IP | 端口 |
消息通知推送 | 正式生产环境 | 无 | 120.25.168.36 | 随机 |
消息通知推送 | 沙箱模拟环境 | 无 | 120.25.168.36 | 随机 |