API接口文档

证书申请-个人证书

传入身份信息,进行证书的申请。

一、公共参数

-
请求地址:http://api.ca.demo.smartcert.cn/apihttp://api.ca.demo.smartcert.cn/api

二、请求参数(请求方式为 post)

名称 类型 是否必须 描述
request PersonalIssueRequest 个人高级证书签发请求

PersonalIssueRequest 说明:

名称 类型 是否必须 描述
personalSeniorCertificate PersonalSeniorCertificate 个人高级证书实体信息
pkCS10 String 用于制作证书的 pkCS10
personVerifyMode PersonVerifyMode 个人认证方式
noticeUrl String 服务器通知地址(点我查看详细使用),当证书申请成功或失败时,会通过此地址通知用户。
successUrl String h5成功页面,不可携带请求参数(点我查看详细使用)

PersonalSeniorCertificate (继承自 BaseCertificate) 说明:

名称 类型 是否必须 描述
idType IdType 证件类型
idNumber String 证件号,需要与证件类型匹配
phoneNumber String 联系号码,若需使用短信核验,则必填
ownerName String 证书持有者姓名

BaseCertificate 说明:

名称 类型 是否必须 描述
organization String 证书 O 项,证书所属组织
organizationUnit String 证书 OU 项,证书所属组织单元
country String 证书 C 项,国家,默认 CN
province String 证书 S 项,证书所属省
city String 证书 L 项,证书所属市
districtCounty String 证书所属区县
givenName String 名字,证书GIVENNAME项
extraExtension List<Extension> 证书扩展项

Extension 说明:

名称 类型 描述
oid String 扩展项oid值
value String 扩展项值
name String 扩展项名称

证件类型(IdType)说明:

名称 描述
ID 身份证
PASSPORT 护照
MILITARY_ID 军人身份证
BUSINESS_REGISTRATION_CERT 工商登记证
TAX_REGISTRATION_CERT 税务登记证
SHAREHOLDER_CODE_CERT 股东代码证
SOCIAL_SECURITY_CARD 社会保障卡
ARMED_POLICE 武装警察身份证件
HK_MACAU_PASSPORT 港澳居民往来内地通行证
TAIWAN_PASSPORT 台湾居民往来内地通行证
HOUSEHOLD_REGISTER 户口簿
TEMPORARY_ID 临时身份证
POLICE_CERT 警官证
PERMANENT_RESIDENCE_PERMIT 外国人永久居留证
GOVERNMENT_APPROVAL 政府批文
UNIFIED_SOCIAL_CERT 统一社会信用代码证
PRIVATE_NON_ENTERPRISE_CERT 民办非企业登记证书
CORPORATE_CERT 法人证书
OTHER 其他

个人认证方式(PersonVerifyMode)说明:

名称 描述
FACE_VERIFY 人脸核验
SMS_VERIFY 短信核验

请求示例:

http://api.ca.demo.smartcert.cn/api
Content-Type: application/x-www-form-urlencoded;charset=utf-8

idType=XXX&...<[业务请求参数]>...&<[公共请求参数]>

三、响应参数

data 结果信息 类型 描述
message String 业务描述
incorrect String 业务返回码
code String 业务码,后续获取结果使用
h5Url String H5签发链接
expireTime Long 过期时间

四、成功示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "证书申请请求成功",
"incorrect": 0,
"code": "5f1...",
"h5Url": "...",
"expireTime": 1776145582054
},
"message": "success"
}

五、失败示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "证书签发失败,P10校验失败",
"incorrect": 1
},
"message": "success"
}

六、返回码说明(incorrect)

返回码 描述
0 证书申请请求成功
其它 参考异常代码表

证书申请-企业证书

传入企业信息,进行证书的申请和签发。

一、请求说明

-
请求地址:http://api.ca.demo.smartcert.cn/apihttp://api.ca.demo.smartcert.cn/api

二、请求参数(请求方式为 post)

名称 类型 是否必须 描述
request EnterpriseIssueRequest 企业证书签发请求

EnterpriseIssueRequest 说明:

名称 类型 是否必须 描述
enterpriseSeniorCertificate EnterpriseSeniorCertificate 企业高级证书实体信息
pkCS10 String 用于制作证书的 pkCS10
personVerifyMode PersonVerifyMode 个人认证方式
agentInfo AgentInfo 经办人信息
legalInfo LegalInfo 法人信息
duration String 证书有效期,格式为数字+字母,字母支持YMDHm,分别对应年月日时分,不传默认1Y。
noticeUrl String 服务器通知地址(点我查看详细使用),当证书申请成功或失败时,会通过此地址通知用户。
successUrl String h5成功页面,不可携带请求参数(点我查看详细使用)

EnterpriseSeniorCertificate (继承自 BaseCertificate) 说明:

名称 类型 是否必须 描述
enterprise String 企业名称
department String 部门名称
idType IdType 证件类型
idNumber String 证件号,需要与证件类型匹配
phoneNumber String 联系号码
ownerName String 证书持有者姓名

BaseCertificate 说明:

名称 类型 是否必须 描述
organization String 证书 O 项,证书所属组织
organizationUnit String 证书 OU 项,证书所属组织单元
country String 证书 C 项,国家,默认 CN
province String 证书 S 项,证书所属省
city String 证书 L 项,证书所属市
districtCounty String 证书所属区县
givenName String 名字,证书GIVENNAME项
extraExtension List<Extension> 证书扩展项

Extension 说明:

名称 类型 描述
oid String 扩展项oid值
value String 扩展项值
name String 扩展项名称

证件类型(IdType)说明:

名称 描述
ID 身份证
PASSPORT 护照
MILITARY_ID 军人身份证
BUSINESS_REGISTRATION_CERT 工商登记证
TAX_REGISTRATION_CERT 税务登记证
SHAREHOLDER_CODE_CERT 股东代码证
SOCIAL_SECURITY_CARD 社会保障卡
ARMED_POLICE 武装警察身份证件
HK_MACAU_PASSPORT 港澳居民往来内地通行证
TAIWAN_PASSPORT 台湾居民往来内地通行证
HOUSEHOLD_REGISTER 户口簿
TEMPORARY_ID 临时身份证
POLICE_CERT 警官证
PERMANENT_RESIDENCE_PERMIT 外国人永久居留证
GOVERNMENT_APPROVAL 政府批文
UNIFIED_SOCIAL_CERT 统一社会信用代码证
PRIVATE_NON_ENTERPRISE_CERT 民办非企业登记证书
CORPORATE_CERT 法人证书
OTHER 其他

个人认证方式(PersonVerifyMode)说明:

名称 描述
FACE_VERIFY 人脸核验
SMS_VERIFY 短信核验

经办人信息(AgentInfo) 说明:

名称 类型 是否必须 描述
agentName String 经办人姓名
agentId String 经办人身份证号
agentPhone String 经办人手机号码,若需使用短信核验,则必填

法人信息(LegalInfo) 说明:

名称 类型 是否必须 描述
legalName String 法人姓名
legalIdCard String 法人身份证号
legalPhone String 法人手机号码

请求示例:

http://api.ca.demo.smartcert.cn/api
Content-Type: application/x-www-form-urlencoded;charset=utf-8

idType=XXX&...<[业务请求参数]>...&<[公共请求参数]>

三、响应参数

data 结果信息 类型 描述
message String 业务描述
incorrect String 业务返回码
code String 业务码,后续获取结果使用
h5Url String H5签发链接
expireTime Long 过期时间

四、成功示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "证书申请请求成功",
"incorrect": 0,
"code": "5f1...",
"h5Url": "...",
"expireTime": 1776145582054
},
"message": "success"
}

五、失败示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "证书签发失败,...",
"incorrect": 1
},
"message": "success"
}

六、返回码说明(incorrect)

返回码 描述
0 证书申请请求成功
其它 参考异常代码表

证书申请 - 获取申请状态

传入证书申请业务码,获取申请状态。

一、公共参数

-
请求地址:http://api.ca.demo.smartcert.cn/apihttp://api.ca.demo.smartcert.cn/api

二、请求参数(请求方式为 post)

名称 类型 是否必须 描述
code String 业务码

请求示例:

http://api.ca.demo.smartcert.cn/api
Content-Type: application/x-www-form-urlencoded;charset=utf-8

code=XXX&...<[业务请求参数]>...&<[公共请求参数]>

三、响应参数

data 结果信息 类型 描述
message String 业务描述
incorrect String 业务返回码
code String 业务码
h5Url String H5页面地址
state String 证书申请状态

证书申请状态(state)说明:

名称 描述
CREATED 已创建- 初始状态
INFO_CONFIRMED 证书信息已确认
MATERIAL_REVIEWING 材料审核中
MATERIAL_APPROVED 材料审核通过
MATERIAL_REJECTED 材料审核驳回
VERIFICATION_PROCESSING 身份核验中
AGREEMENT_PENDING 待签署协议
AGREEMENT_SIGNED 协议已签署
OVER 已完成

四、成功示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "success",
"incorrect": 0,
"code": "xxx",
"h5Url": "xxx",
"state": "VERIFICATION_PROCESSING"
},
"message": "success"
}

五、失败示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "获取申请状态失败",
"incorrect": 1
},
"message": "success"
}

六、返回码说明(incorrect)

返回码 描述
0 证书申请状态请求成功
1 证书申请记录状态异常
2 证书申请已取消
3 证书申请已过期
其它 参考异常代码表

证书申请 - 获取申请结果

传入证书申请业务码,获取申请结果。

一、公共参数

-
请求地址:http://api.ca.demo.smartcert.cn/apihttp://api.ca.demo.smartcert.cn/api

二、请求参数(请求方式为 post)

名称 类型 是否必须 描述
code String 业务码

请求示例:

http://api.ca.demo.smartcert.cn/api
Content-Type: application/x-www-form-urlencoded;charset=utf-8

code=XXX&...<[业务请求参数]>...&<[公共请求参数]>

三、响应参数

data 结果信息 类型 描述
message String 业务描述
incorrect String 业务返回码
certId String 证书 ID
signatureCert String 签名证书
encryptionCert String 加密证书
encryptionPrivateKey String 加密私钥

四、成功示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "证书签发成功",
"incorrect": 0,
"signatureCert": "RFG...",
"encryptionCert": "DCF1...",
"encryptionPrivateKey": "DFXSS...",
"certId": "SD1..."
},
"message": "success"
}

五、失败示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "证书签发失败,P10校验失败",
"incorrect": 1
},
"message": "success"
}

六、返回码说明(incorrect)

返回码 描述
0 证书申请请求成功
其它 参考异常代码表

证书注销

输入证书标识,注销证书。

一、公共参数

二、请求参数

名称 类型 是否必须 描述
request RevokeRequest 证书注销请求

RevokeRequest 说明

名称 类型 是否必须 描述
certId String 证书唯一标识
extensions Map 扩展属性

请求示例:

http或https://222.190.151.234:2016/api?

&certId=XXX

&<[公共请求参数]>

三、响应参数

业务响应名称 类型 描述
incorrect String 结果响应码
message String 注销说明
certId String 证书 ID
result Boolean 注销结果
extensions Map<String,String> 扩展项

四、成功示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "注销成功",
"certId": "sd34df...",
"result": "true",
"incorrect": 0,
"extensions": "{orderId=dsd24...}"
},
"message": "success"
}

五、失败示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "注销失败,证书非可用状态",
"incorrect": 1,
"result": "false",
"certId": "sd34df..."
},
"message": "success"
}

六、返回码说明(incorrect)

返回码 描述
0 证书注销成功
其它 参考异常代码表

证书延期

输入证书标识和需要延期的天数,对该证书进行延期。

一、公共参数

-
请求地址:http://api.ca.demo.smartcert.cn/apihttp://api.ca.demo.smartcert.cn/api

二、请求参数

名称 类型 是否必须 描述
request PostponeRequest 证书延期请求

PostponeRequest 说明:

名称 类型 是否必须 描述
certId String 证书唯一标识
pkCS10 String 用于制作证书的 pkCS10
duration String 证书延期时间,格式为数字+字母,字母支持YMDHm,分别对应年月日时分,不传默认1Y。
userOldKey Boolean 是否使用原密钥对,默认为 True(此选项针对加密证书密钥对)
extensions Map 扩展属性

请求示例:

http或https://222.190.151.234:2016/api?

&certId=XXX

&duration=2M

&<[公共请求参数]>

三、响应参数

data 结果信息 类型 描述
signatureCert String 签名证书
encryptionCert String 加密证书
encryptionPrivateKey String 加密私钥
certId String 证书 ID
message String 业务响应描述
incorrect String 业务返回码
extensions Map<String,String> 扩展项

四、成功示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "延期成功",
"incorrect": 0,
"signatureCert": "ECS24S...",
"encryptionCert": "ECS24S...",
"encryptionPrivateKey": "ECS24S...",
"certId": "ECS24S...",
"extensions": "{orderId=dsd24...}"
},
"message": "success"
}

五、失败示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "延期失败,延期天数超过5年.",
"incorrect": 1,
"certId": "ECS24S..."
},
"message": "success"
}

六、返回码说明(incorrect)

返回码 描述
0 延期成功
其它 参考异常代码表

证书重发

传入证书标识和介质 P10,对相应证书做重发。

一、公共参数

-
请求地址:http://api.ca.demo.smartcert.cn/apihttp://api.ca.demo.smartcert.cn/api

二、请求参数(请求方式为 post)

名称 类型 是否必须 描述
request ReissueRequest 证书重发请求

ReissueRequest 说明

名称 类型 是否必须 描述
certId String 证书 id
pkCS10 String 用于制作证书的 pkCS10 (建议使用)
userOldKey Boolean 是否使用原密钥对,默认为 True(此选项针对加密证书密钥对)
extensions Map 扩展属性

请求示例:

http://api.ca.demo.smartcert.cn/api
Content-Type: application/x-www-form-urlencoded;charset=utf-8

certId=XXX&pkCS10=XXX&<[公共请求参数]>

三、响应参数

data 结果信息 类型 描述
message String 描述
incorrect String 返回码
signatureCert String 签名证书
encryptionCert String 加密证书
encryptionPrivateKey String 加密私钥
certId String 证书 ID
extensions Map<String,String> 扩展项

四、成功示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "证书重发成功",
"incorrect": 0,
"signatureCert": "DCF1...",
"encryptionCert": "DCF1...",
"encryptionPrivateKey": "ECS24S...",
"certId": "SD1...",
"extensions": "{orderId=dsd24...}"
},
"message": "success"
}

五、失败示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "证书重发失败,该证书已被注销",
"incorrect": 1,
"certId": "SD1..."
},
"message": "success"
}

六、返回码说明(incorrect)

返回码 描述
0 证书重发成功
其它 参考异常代码表

证书密钥恢复

传入证书标识和介质 P10,对相应证书进行密钥恢复。

一、公共参数

-
请求地址:http://api.ca.demo.smartcert.cn/apihttp://api.ca.demo.smartcert.cn/api

二、请求参数(请求方式为 post)

名称 类型 是否必须 描述
request RecoverRequest 证书密钥恢复请求

ReissueRequest 说明

名称 类型 是否必须 描述
certId String 证书 id
pkCS10 String 用于制作证书的 pkCS10
extensions Map 扩展属性

请求示例:

http://api.ca.demo.smartcert.cn/api
Content-Type: application/x-www-form-urlencoded;charset=utf-8

certId=XXX&pkCS10=XXX&<[公共请求参数]>

三、响应参数

data 结果信息 类型 描述
message String 描述
incorrect String 返回码
encryptionCert String 加密证书
encryptionPrivateKey String 加密私钥
signatureCert String 签名证书
certId String 证书 ID
extensions Map<String,String> 扩展项

四、成功示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "success",
"incorrect": 0,
"encryptionCert": "DCF1...",
"encryptionPrivateKey": "ECS24S...",
"certId": "SD1...",
"extensions": "{orderId=dsd24...}"
},
"message": "success"
}

五、失败示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"message": "证书密钥恢复失败,该证书已被注销",
"incorrect": 1,
"certId": "SD1..."
},
"message": "success"
}

六、返回码说明(incorrect)

返回码 描述
0 证书密钥恢复成功
其它 参考异常代码表

根据id查询证书

传入证书id,精确查询证书。

一、公共参数

-
请求地址:http://api.ca.demo.smartcert.cn/apihttp://api.ca.demo.smartcert.cn/api

二、请求参数(请求方式为 post)

名称 类型 是否必须 描述
request CertQueryByIdRequest 根据证书id查询证书请求

CertQueryByIdRequest 说明:

名称 类型 是否必须 描述
certId String 待查询证书的标识

请求示例:

http://api.ca.demo.smartcert.cn/api
Content-Type: application/x-www-form-urlencoded;charset=utf-8
cerId=XXX&...<[业务请求参数]>...&<[公共请求参数]>

三、响应参数

data 结果信息 类型 描述
certJson String 证书对象json 格式

四、成功示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": {
"idType": "ID...",
"idNumber": "32012...",
"phoneNumber": "173111...",
"ownerName": "liubei...",
"certificateType": "ENTERPRISE_SENIOR",
"enterprise": "XX...",
"department": "XX",
"subject": "CN=XX,OU=XX,O=XX,ST=XX,L=XX,C=CN",
"id": "api_ca_e...",
"commonName": "XX...",
"organization": "XX...",
"organizationUnit": "XX...",
"country": "XX...",
"province": "XX...",
"city": "XX...",
"districtCounty": "XX...",
"notBefore": "Mon Oct 01 22:36:01 CST 2018",
"notAfter": "Thu Oct 01 22:36:01 CST 2020",
"email": "zhugeliang@han.cn"
},
"message": "success"
}

五、失败示例

JSON示例

{
"code": 0,
"requestId": "dsd24...",
"data": null,
"message": "success"
}

六、返回码说明(incorrect)

返回码 描述
0 证书查询成功
其它 参考异常代码表

回调通知接口示例

当申请证书结束后,平台服务器会向用户提供的noticeUrl参数地址向用户发送 HTTP 通知。

用户在接收到参数时,需要对参数进行验签,在确认无误的情况下,向实名认证系统返回”success”字符串。

参数说明

属性 类型 描述
appKey String 身份标识
timestamp String 时间戳
nonce String 随机数
version String API 版本号,目前版本是 1
signMethod String 签名算法,默认HMAC-SHA256
sign String 签名值
code String 业务码
state String 状态
encryptionCert String 加密证书,state为 OVER时返回
encryptionPrivateKey String 加密私钥,state为 OVER时返回
signatureCert String 签名证书,state为 OVER时返回
certId String 证书 ID,state为 OVER时返回

state参数说明

state 描述
OVER 已完成,可获取证书信息
ERROR 异常

回调通知接口示例

@PostMapping("/callback")
public String callback(HttpServletRequest request) {
String appSecret = "应用密钥";

Map<String, String> paramMap = new HashMap<>();

//公共参数
paramMap.put("appKey", request.getParameter("appKey"));
paramMap.put("timestamp", request.getParameter("timestamp"));
paramMap.put("nonce", request.getParameter("nonce"));
paramMap.put("version", request.getParameter("version"));
paramMap.put("signMethod", request.getParameter("signMethod"));
paramMap.put("sign", request.getParameter("sign"));

//具体接口参数
paramMap.put("code", request.getParameter("code"));

String state = request.getParameter("state");
paramMap.put("state", state);
// 如果state为over,则包含证书信息
if (StringUtils.equalsIgnoreCase(state, "OVER")) {
paramMap.put("signatureCert", request.getParameter("signatureCert"));
paramMap.put("encryptionCert", request.getParameter("encryptionCert"));
paramMap.put("encryptionPrivateKey", request.getParameter("encryptionPrivateKey"));
paramMap.put("certId", request.getParameter("certId"));
}

String signContent = SignUtils.getSignatureContent(paramMap);
System.out.println("signContent = " + signContent);

boolean check = SignUtils.signCheck(paramMap, appSecret, "UTF-8", SignUtils.SIGN_TYPE_HMAC_SHA_256);
if (!check) {
System.err.println("验签失败");
return "fail";
}
// todo 业务逻辑

// 返回通知成功,固定值success
return "success";
}

url跳转说明

在配置successUrl的情况下,流程结束时会进行页面跳转,跳转时会以query的方式在url后拼接参数。

用户在接收到参数时,需要对参数进行验签。

参数示例

https://www.smartcert.cn/ 为跳转示例,生成如下url

https://www.smartcert.cn/?code=xxxxx&sign=3A9512A018B9709764CCB9CC1E0D0B7BF83C2A47E8DD3563D195B9F520AA1B17&appKey=xxxx&state=OVER&nonce=oaUDl2Gror&version=1&signMethod=HMAC-SHA256&timestamp=1777346392048

参数说明

属性 描述
code 业务码
sign 签名
appKey 应用标识
state 状态
nonce 随机字符串
version 版本
signMethod 签名方法
timestamp 时间戳

url验签

   /**
* 跳转url验签示例
*/
@RequestMapping(value = "/callback", method = {RequestMethod.GET})
public void callback(HttpServletRequest request) {
Map<String, String> paranMap = Maps.newHashMap();
//公共参数
paranMap.put("appKey", request.getParameter("appKey"));
paranMap.put("state", request.getParameter("state"));
paranMap.put("nonce", request.getParameter("nonce"));
paranMap.put("version", request.getParameter("version"));
paranMap.put("timestamp", request.getParameter("timestamp"));
paranMap.put("signMethod", request.getParameter("signMethod"));
paranMap.put("sign", request.getParameter("sign"));

paranMap.put("code", request.getParameter("code"));
String appSecret = "应用密钥";

//验签
boolean check = SignUtils.signCheck(paramMap, appSecret, "UTF-8", SignUtils.SIGN_TYPE_HMAC_SHA_256);
if (check) {
// todo 验签成功,获取结果

}
}

签名验签工具类

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.*;

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 appSecret
* @param charset
* @param signType
* @return
*/
public static boolean signCheck(Map<String, String> paranMap, String appSecret, 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(appSecret, content, charset, SIGN_TYPE_HMAC_SHA_1));
} else {
return sign.equals(computeSignature(appSecret, 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 = new TreeMap<>();

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();
}

}