# 企业对公打款认证API
# 业务介绍
企业对公打款认证API是通过企业的对公账户及企业的打款动作来核验企业信息的真实性,可搭配其他企业身份认证方式使用,以提高企业认证的安全性及可信度。
打款金额在0.01~1
元之间
注意: 打款金额,概不退款!
# 获取 Token
根据传入的sdk的信息生成认证token
# 一、请求说明
请求地址:http://api.spiderid.cn/api/router/rest,https://api.spiderid.cn/api/router/rest
服务接口名称(即公共参数method的值): entauth.bankpay.getToken
请求方式:GET,POST
# 二、请求参数
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
entName | String | 是 | 企业名称 |
entBankNumber | String | 是 | 企业对公账号 |
paymentPurpose | String | 否 | 打款附言(如果填写,打款时必须填写相同的附言) |
notifyUrl | String | 否 | 服务器通知地址(点我查看详细使用) |
请求示例:
https://api.spiderid.cn/api/router/rest?
entName=XXX
&entBankNumber=XXX
&<[公共请求参数]>
# 三、响应参数
data 结果信息 | 类型 | 描述 |
---|---|---|
incorrect | Integer | 返回码(详情见字段解释) |
token | String | 认证Token |
message | String | 对返回码的描述 |
receivingPaymentAccountName | String | 收款户名 |
receivingPaymentBankName | String | 收款开户行名称 |
receivingPaymentBank | String | 收款银行 |
receivingPaymentUnionNo | String | 收款联行号 |
receivingPaymentEntName | String | 收款公司名称 |
receivingPaymentAccount | String | 收款银行账号 |
amount | String | 打款金额 |
purpose | String | 打款时附言 |
字段解释
incorrect 返回码介绍
字段 | 状态介绍 |
---|---|
100 | 成功 |
# 四、成功示例
JSON示例
{
"code": 0,
"requestId":"f1006...",
"message": "success",
"data": {
"amount": "0.76",
"incorrect": 100,
"message": "成功",
"receivingPaymentAccount": "3116**3140",
"receivingPaymentAccountName": "收款户名",
"receivingPaymentBank": "**银行",
"receivingPaymentBankName": "**银行",
"receivingPaymentEntName": "**公司",
"receivingPaymentUnionNo": "**123",
"token": "f1006..."
"purpose": "123..."
}
}
# 获取认证状态
根据token获取认证状态
# 一、请求说明
请求地址:http://api.spiderid.cn/api/router/rest,https://api.spiderid.cn/api/router/rest
服务接口名称(即公共参数method的值): entauth.bankpay.getStatus
请求方式:GET,POST
# 二、请求参数
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
token | String | 是 | 认证token |
请求示例:
https://api.spiderid.cn/api/router/rest?
token=XXX
&<[公共请求参数]>
# 三、响应参数
data 结果信息 | 类型 | 描述 |
---|---|---|
status | String | 认证状态 |
incorrect | Integer | 返回码(详情见字段解释) |
message | String | 对返回码的描述 |
字段解释
status 认证状态介绍
字段 | 状态介绍 |
---|---|
ACTION | 认证中 |
SUCCESS | 认证成功 |
FAILURE | 认证失败 |
INVALID | 认证超时 |
- incorrect 返回码介绍
字段 | 状态介绍 |
---|---|
100 | 成功 |
101 | 认证记录不存在 |
# 四、成功示例
JSON示例
{
"code": 0,
"requestId":"f1006...",
"message": "success",
"data": {
"status":"SUCCESS",
"incorrect":100,
"message":"成功"
}
}
# 五、失败示例
JSON示例
{
"code": 0,
"requestId":"f1006...",
"message": "success",
"data": {
"incorrect":101,
"message":"认证记录不存在"
}
}
# 获取认证结果
根据token获取认证结果。
请求地址:http://api.spiderid.cn/api/router/rest,https://api.spiderid.cn/api/router/rest
服务接口名称(即公共参数method的值): entauth.bankpay.getResult
请求方式:GET,POST
# 二、请求参数
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
token | String | 是 | 认证token |
请求示例:
https://api.spiderid.cn/api/router/rest?
token=XXX
&<[公共请求参数]>
# 三、响应参数
data 结果信息 | 类型 | 描述 |
---|---|---|
amount | String | 打款金额 |
incorrect | Integer | 返回码(详情见字段解释) |
message | String | 对返回码的描述 |
paymentTime | String | 打款日期 |
purpose | String | 打款附言 |
字段解释
incorrect 返回码介绍
字段 | 状态介绍 |
---|---|
100 | 成功 |
101 | 认证记录不存在 |
102 | 认证状态非法 |
103 | 认证失败 |
104 | 认证超时 |
# 四、成功示例
JSON示例
{
"code": 0,
"requestId":"f1006...",
"message": "success",
"data": {
"amount":"0.32",
"incorrect":100,
"message":"成功",
"paymentTime": "2021-10-13 10:31:58",
"purpose": "123..."
}
}
# 五、失败示例
JSON示例
{
"code": 0,
"requestId":"f1006...",
"message": "success",
"data": {
"incorrect":103,
"message":"认证失败"
}
}
# SDK 请求示例
# 获取token
//提供的url
String url = "http://api.spiderid.cn/api/router/rest";
//您的appKey
String appkey = "XXX";
//您的appSecret
String secretKey = "XXX";
//1.原客户端
ApiClient apiClient = new DefaultApiClient(url, appkey, secretKey);
//2.调用出错,自动重试客户端
EntAuthBankpayGetTokenRequest req = new EntAuthBankpayGetTokenRequest();
req.setEntName("xxx公司");
req.setEntBankNumber("123...");
//打款附言 (选填)
//req.setPaymentPurpose();
//平台方服务器主动通知客户服务器指定地址,向服务器主动推送验证结果(选填)
//req.setNotifyUrl();
try {
EntAuthBankpayGetTokenResponse response = apiClient.execute(req);
//后续业务处理
} catch (ApiException e) {
e.printStackTrace();
}
}
# 获取认证状态
//提供的url
String url = "http://api.spiderid.cn/api/router/rest";
//您的appKey
String appkey = "XXX";
//您的appSecret
String secretKey = "XXX";
//1.原客户端
ApiClient apiClient = new DefaultApiClient(url, appkey, secretKey);
//2.调用出错,自动重试客户端
EntAuthBankpayGetStatusRequest req = new EntAuthBankpayGetStatusRequest();
//认证token
req.setToken("XXX");
try {
EntAuthBankpayGetStatusResponse response = apiClient.execute(req);
//后续业务处理
} catch (ApiException e) {
e.printStackTrace();
}
}
# 获取认证结果
//提供的url
String url = "http://api.spiderid.cn/api/router/rest";
//您的appKey
String appkey = "XXX";
//您的appSecret
String secretKey = "XXX";
//1.原客户端
ApiClient apiClient = new DefaultApiClient(url, appkey, secretKey);
//2.调用出错,自动重试客户端
EntAuthBankpayGetResultRequest req = new EntAuthBankpayGetResultRequest();
//认证token
req.setToken("xxx");
try {
EntAuthBankpayGetResultResponse response = apiClient.execute(req);
//后续业务处理
} catch (ApiException e) {
e.printStackTrace();
}
# 回调通知接口示例
当企业打款认证流程结束后,平台服务器会向开发者提供的notifyUrl
参数地址向开发者发送 HTTP 通知。
开发者在接收到参数时,需要对参数进行验签,在确认无误的情况下,返回"success"字符串。
/**
* 回调通知示例
*
* @param request
*/
public String notify(HttpServletRequest request) {
Map<String, String> paranMap = Maps.newHashMap();
//公共参数
paranMap.put("appKey", request.getParameter("appKey"));
paranMap.put("signType", request.getParameter("signType"));
paranMap.put("notifyTime", request.getParameter("notifyTime"));
paranMap.put("notifyId", request.getParameter("notifyId"));
paranMap.put("version", request.getParameter("version"));
paranMap.put("requestId", request.getParameter("requestId"));
paranMap.put("sign", request.getParameter("sign"));
String appSecret = "应用密钥";
//验签
boolean res = SignUtils.signCheck(paranMap, appSecret, SignUtils.CHARSET, request.getParameter("signType"));
log.info("验签结果为: {}", res ? "验签成功" : "验签失败");
if (res) {
//验签成功
// 可以获取认证结果了
//返回通知成功
return "success";
}
// 验签失败 可以给一个异常
return "fail";
}
# 验签工具类
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* 验签工具类
*/
public class SignUtils {
public final static String SIGN_TYPE_HMAC_SHA_1 = "HmacSHA1";
public final static String SIGN_TYPE_HMAC_SHA_256 = "HmacSHA256";
public final static String REQUEST_PUBLIC_PARAMS_SIGN = "sign";
public final static String CHARSET = "UTF-8";
private static final Object LOCK = new Object();
/**
* Prototype of the Mac instance.
*/
private static Mac macInstance;
/**
* 验签
*
* @param paranMap
* @param secretKey
* @param charset
* @param signType
* @return
*/
public static boolean signCheck(Map<String, String> paranMap, String secretKey, String charset, String signType) {
// 字典排序
String sign = paranMap.get(REQUEST_PUBLIC_PARAMS_SIGN);
String content = getSignCheckContentV1(paranMap);
if (SIGN_TYPE_HMAC_SHA_1.equals(signType)) {
return sign.equals(computeSignature(secretKey, content, charset, SIGN_TYPE_HMAC_SHA_1));
} else {
return sign.equals(computeSignature(secretKey, content, charset, SIGN_TYPE_HMAC_SHA_256));
}
}
public static String getSignCheckContentV1(Map<String, String> params) {
if (params == null) {
return null;
}
params.remove(REQUEST_PUBLIC_PARAMS_SIGN);
return getSignatureContent(params);
}
public static String getSignatureContent(Map<String, String> paranMap) {
return getSignContent(getSortedMap(paranMap));
}
public static Map<String, String> getSortedMap(Map<String, String> paranMap) {
Map<String, String> sortedParams = Maps.newTreeMap();
paranMap.keySet().stream()
.sorted()
.forEach(sortKey -> sortedParams.put(sortKey, paranMap.get(sortKey)));
return sortedParams;
}
/**
* @param sortedParams
* @return
*/
public static String getSignContent(Map<String, String> sortedParams) {
StringBuffer content = new StringBuffer();
List<String> keys = new ArrayList<String>(sortedParams.keySet());
Collections.sort(keys);
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = sortedParams.get(key);
if (StringUtils.isNotEmpty(key) && StringUtils.isNotEmpty(value)) {
content.append(key).append(value);
}
}
return content.toString();
}
public static String computeSignature(String key, String data, String charset, String algorithm) {
try {
byte[] signData = sign(key.getBytes(charset), data.getBytes(charset), algorithm);
return byte2hex(signData);
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException("Unsupported algorithm: " + charset, ex);
}
}
private static byte[] sign(byte[] key, byte[] data, String algorithm) {
try {
// Because Mac.getInstance(String) calls a synchronized method, it could block on
// invoked concurrently, so use prototype pattern to improve perf.
if (macInstance == null) {
synchronized (LOCK) {
if (macInstance == null) {
macInstance = Mac.getInstance(algorithm);
}
}
}
Mac mac = null;
try {
mac = (Mac) macInstance.clone();
} catch (CloneNotSupportedException e) {
// If it is not clonable, create a new one.
mac = Mac.getInstance(algorithm);
}
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data);
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException("Unsupported algorithm: " + algorithm, ex);
} catch (InvalidKeyException ex) {
throw new RuntimeException("Invalid key: " + key, ex);
}
}
/**
* 把字节流转换为十六进制表示方式。
*/
protected static String byte2hex(byte[] bytes) {
StringBuilder sign = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
sign.append("0");
}
sign.append(hex.toUpperCase());
}
return sign.toString();
}
}
← 获取可信时间戳 企业对公收款认证API →