关于签名

说明

  • 目前采取线下方式或商户管理平台获取到secrete;
  • secrete:是用于对 API 请求的输入参数进行摘要和签名的,商户自行保管且需严格保证此秘钥的安全性,不可对外泄露;
  • 生成签名串:将所有需要验签的参数,组成一个数组,并按所有参数名的字典序(ASCII码)升序排序,注意只有参数的 key 名进行排序,值不参与排序。
  • 所有必填字段值参与签名(不包含sign)。

签名串示例

如参数:

{
  "email": "[email protected]",
  "appId": "qmamnbodyqzbdr0w"
}

拼接字符串做签名准备,将格式转化为参数名=参数值形式,并用&符链接,最后再追加上key(secrete),结果如下:

appId=qmamnbodyqzbdr0w&[email protected]&key=6fdbaac29eb94bc6b36547ad705e9298

接着对待加签字符串 做 SHA-512 算法进行摘要签名,生成最终的签名, 签名结果如下:

 8979EEB59CF15246A04E033962CA4084973A9D0F2F5CC08F07B99E9D0338F4486ED7700CF78F6365C2E399ED593B3EF9059F2EC808B5107CED8CC17BA0475962J

java签名生成代码示例:

package io.alchemytech.virtualcard.center.utils;
import io.alchemytech.basics.shared.common.utils.SHA512Utils;
import java.util.SortedMap;
import java.util.TreeMap;

public class SignUtils {
    /**
     * @param appId 商户号
     * @param email      email
     * @param secrete    秘钥
     * @return
     */
    public static String getSign(String appId, String email, String secrete) {
        SortedMap<Object, Object> map = new TreeMap<>();
        if (email != null && !email.equals("")) {
            map.put("email", email);
        }
        map.put("appId", appId);
        String sign = SHA512Utils.SHAEncrypt(map, secrete);
        return sign;
    }

    public static void main(String[] args) {
        System.out.println(getSign("qmamnbodyqzbdr0w","[email protected]","6fdbaac29eb94bc6b36547ad705e9298"));
    }
}

加密工具类:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
public class SHA512Utils {
    public static final String ENCODE = "UTF-8";
    private static Logger logger = LoggerFactory.getLogger(SHA512Utils.class);

    /**
     * 对报文进行SHA签名
     *
     * @param signParams 签名参数
     * @param key        密钥
     * @return
     */
    public static String SHAEncrypt(SortedMap<Object, Object> signParams, String key) {
        String sign = null;
        StringBuffer sb = new StringBuffer();
        Set es = signParams.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !v.equals("null") && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + key);
        logger.info("signStr: {}", sb);
        sign = encrypt(sb.toString(), ENCODE).toUpperCase();
        logger.info("sign: {}", sign);
        return sign;
    }

    public static String encrypt(String aValue, String encoding) {
        aValue = aValue.trim();
        byte value[];
        try {
            value = aValue.getBytes(encoding);
        } catch (UnsupportedEncodingException e) {
            value = aValue.getBytes();
        }
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA-512");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
        return toHex(md.digest(value));
    }

    public static String toHex(byte input[]) {
        if (input == null) return null;
        StringBuffer output = new StringBuffer(input.length * 2);
        for (int i = 0; i < input.length; i++) {
            int current = input[i] & 0xff;
            if (current < 16) output.append("0");
            output.append(Integer.toString(current, 16));
        }
        return output.toString();
    }

    /**
     * 验签
     *
     * @param signParams 签名参数
     * @param key        密钥
     * @return
     */
    public static boolean verifySHA(SortedMap<Object, Object> signParams, String key) {
        String verifySign = (String) signParams.get("sign");
        String sign = SHAEncrypt(signParams, key);
        if (sign.equalsIgnoreCase(verifySign)) {
            return true;
        }
        return false;
    }
}