# Sign方式(非对称加密)

需要申请对应环境的appKeyappSecret

测试域名: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();
    }