# Sign方式(非对称加密)
需要申请对应环境的appKey与appSecret
测试域名:https://openapi-test.babycare.com/api/gateway
正式域名:https://gateway.babycare.com
所有请求地址分为三段:网关+路由+接口地址,路由和接口地址由开发人员提供
示例某接口地址:https://openapi-test.babycare.com/api/gateway/open/v6/platform/list
- 网关为:https://openapi-test.babycare.com/api/gateway
- 路由为:/open/v6
- 接口地址:/platform/list
已过时版本(存在会导致签名错误的场景),虽然可以继续使用,但是建议联系对应人员升级最新
# 1、请求的公共参数(Header)
| 名称 | 类型 | 必填 | 描述 |
|---|---|---|---|
| appKey | String | 是 | 请求应用编码 |
| signRequestId | String | 是 | 请求号(一个随机编码),参与签名 |
| signRequestTime | String | 是 | 请求时间戳(单位:秒),参与签名 |
| signVersion | String | 是 | 5.0 , 参与签名 |
| sign | String | 是 | 签名字符串 |
签名参数是放在header头部中的,不能在url参数拼接或者放在body体中
# 2、签名算法
# 签名⽣成的通⽤步骤如下:
# 第一步:
将所有⾮空请求参数(包括Header中参与签名参数,QueryString参数),按照参数名ASCII码从⼩到⼤排序(字典序),使 ⽤URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
# 注意事项:
1、参数名ASCII码从⼩到⼤排序(字典顺序)
2、如果参数的值为空不参与签名;
3、参数名区分⼤⼩写;
# 第⼆步:
对stringA进行处理
appSecret&stringA&请求body&appSecret得到stringSignTemp字符串,并对stringSignTemp进⾏MD5运算,再将得到的字符串所有字符转 换为⼤写,得到sign值signValue。
# Java代码示例
public static void main(String[] args) {
//访问appKey
String appKey = "申请";
//访问appSecret
String appSecret = "申请";
//版本号 固定值
String signVersion = "5.0";
//服务器地址
String gatewayUrl = "网关地址";
// 构造参数使用treeMap保证构建sign字符串时有序
Map<String, String> allParams = new TreeMap<>();
//基础参数
String signRequestId = UUID.randomUUID().toString();
//秒级时间戳
long signRequestTime = System.currentTimeMillis() / 1000;
//基础加密参数
allParams.put("signVersion", signVersion);
allParams.put("signRequestId", signRequestId);
allParams.put("signRequestTime", signRequestTime + "");
//假设url拼接的参数,也需要放到签名map中
Map<String, String> urlParams = new HashMap<>(1);
urlParams.put("id", "123");
allParams.putAll(urlParams);
//假设请求body
String body = "{\"code\":\"123\"}";
//签名
String sign = sign(allParams, body, appSecret);
//设置header
HttpHeaders headers = setHeaders(appKey, signVersion, signRequestId, signRequestTime, sign);
RestTemplate restTemplate = new RestTemplate();
HttpEntity<String> request = new HttpEntity<>(body, headers);
// /platform/list为业务接口实际地址,/open/v6为网关路由地址需要问开发人员索取
ResponseEntity<Object> entity = restTemplate.exchange
(gatewayUrl + "/open/v6/platform/list?id=123", HttpMethod.POST, request, Object.class);
System.out.println(entity.getBody());
}
private static HttpHeaders setHeaders(String appKey, String signApiVersion, String signRequestId, long signRequestTime, String sign) {
HttpHeaders headers = new HttpHeaders();
headers.set("appKey", appKey);
headers.set("sign", sign);
headers.set("signVersion", signApiVersion);
headers.set("signRequestId", signRequestId);
headers.set("signRequestTime", signRequestTime + "");
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
private static String sign(Map<String, String> params, String body, String secret){
StringJoiner sj = new StringJoiner("&");
sj.add(secret);
for (Map.Entry<String, String> entry : params.entrySet()) {
//字段值为空不拼接
if (org.apache.commons.lang3.StringUtils.isEmpty(entry.getValue())) {
continue;
}
sj.add(entry.getKey() + "=" + entry.getValue());
}
//body不为空append
if(org.apache.commons.lang3.StringUtils.isNotEmpty(body)){
sj.add(body);
}
sj.add(secret);
System.out.println("加密前="+ sj.toString());
return DigestUtils.md5Hex(sj.toString()).toUpperCase();
}