接口签名规则和Java实现签名和验签代码

接口签名规则和Java实现签名和验签代码

签名规则
签名生成的通用步骤如下:
第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意以下重要规则:
◆ 参数名ASCII码从小到大排序(字典序);
◆ 如果参数的值为空不参与签名;
◆ 参数名区分大小写;
◆ 验证接口调用传送的sign参数不参与签名,将生成的签名与该sign值作校验。
第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。 注意:密钥的长度为32个字节。

package com.example.core.mydemo.sign;

import com.example.core.mydemo.MD5;
import org.apache.commons.lang3.StringUtils;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;


public class SignatureTest {

    /**
     * 签名
     * @param map
     * @param key
     * @return
     * @throws Exception
     */
    public static String getSign(Map<String,String> map,String key) throws Exception{
        ArrayList<String> list = new ArrayList<String>();
        for(Map.Entry<String,String> entry:map.entrySet()){
            if(entry.getValue() != null && StringUtils.isNotBlank(entry.getValue().toString()) && !"null".equals(entry.getValue())
            && !"class".equals(entry.getKey()) && !"data".equals(entry.getKey())){
                list.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        int size = list.size();
        String [] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort);
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < size; i ++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        //过滤最后一个字符串&
        int lastIdx = result.lastIndexOf("&");
        result = result.substring(0,lastIdx);
        result +=  key;
        try{
            result = MD5.MD5Encode(result).toUpperCase();
        }catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 验证签名
     * @param map
     * @param key
     * @return
     * @throws Exception
     */
    public static boolean checkIsSignValidFromResponseString(Map<String,String> map,String key) throws Exception {
        String signFromAPIResponse = null;
        if(map.get("sign")!=null){
            signFromAPIResponse = map.get("sign").toString();
        }
        if(signFromAPIResponse=="" || signFromAPIResponse == null){
            return false;
        }
        map.put("sign","");
        map.put("class","");
        //重新签名
        String signForAPIResponse = SignatureTest.getSign(map,key);
        if(!signForAPIResponse.equals(signFromAPIResponse)){
            //签名验不过,表示这个API返回的数据有可能已经被篡改了
            return false;
        }
        return true;
    }

    
    public static void main(String[] args) {
        try {
            //key没有位数的要求
            String key = "1234567890tkltktqVdTstvuhlZHTest";

            //simple test
            Map<String,String> map = new HashMap<String,String>();
            map.put("appId", "0001");
            map.put("userName", "steve");
            map.put("pwd", "123456");
            map.put("sex", "man");
            String sign = SignatureTest.getSign(map,key);
            System.out.println(sign);

            map.put("sign", sign);

            //验证签名
            System.out.println(SignatureTest.checkIsSignValidFromResponseString(map,key));

        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}
package com.example.core.mydemo;

import java.security.MessageDigest;


public class MD5 {
    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
            "8", "9", "a", "b", "c", "d", "e", "f"};

    /**
     * 转换字节数组为16进制字串
     * @param b 字节数组
     * @return 16进制字串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }

    /**
     * 转换byte到16进制
     * @param b 要转换的byte
     * @return 16进制格式
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    /**
     * MD5编码
     * @param origin 原始字符串
     * @return 经过MD5加密之后的结果
     */
    public static String MD5Encode(String origin) {
        String resultString = null;
        try {
            resultString = origin;
            MessageDigest md = MessageDigest.getInstance("MD5");
            resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultString;
    }

}

 

posted on 2023-06-30 18:50  oktokeep  阅读(1770)  评论(0编辑  收藏  举报