Java接口签名和验签

发布时间 2023-09-25 22:58:45作者: oktokeep

Java接口签名和验签

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import java.lang.reflect.Field;
import java.util.*;


public class Signature {

    /**
     * 签名
     * @param object
     * @param key
     * @return
     * @throws Exception
     */
    public static String getSign(Object object,String key) throws Exception {
        Map<String, String> map = objectToMap(object);
        return getSign(map,key);
    }

    private static Map<String, String> objectToMap(Object object) {
        Map<String,String> map = new HashMap<>();
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                map.put(field.getName(), String.valueOf(field.get(object)));
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        return map;
    }


    /**
     * 签名
     * @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())){  //空字符串 entry.getValue()!=""){
                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 object
     * @param key
     * @return
     * @throws Exception
     */
    public static boolean checkIsSignValidFromResyponseStringObject(Object object,String key) throws Exception {
        Map<String, String> map = objectToMap(object);
        return checkIsSignValidFromResponseString(map,key);
    }


    /**
     * 验签
     * @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;
        }
        
        //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
        map.put("sign","");
        map.put("class","");
        //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
        //重新签名
        String signForAPIResponse = Signature.getSign(map,key);
        
        if(!signForAPIResponse.equals(signFromAPIResponse)){
            //签名验不过,表示这个API返回的数据有可能已经被篡改了
            return false;
        }
        return true;
    }

    //test
    static class UserInfo{
        private String userName;
        private String idNo;
        private String mobile;
        private String sign;

        public String getSign() {
            return sign;
        }

        public void setSign(String sign) {
            this.sign = sign;
        }

        public String getUserName() {
            return userName;
        }

        public void setUserName(String userName) {
            this.userName = userName;
        }

        public String getIdNo() {
            return idNo;
        }

        public void setIdNo(String idNo) {
            this.idNo = idNo;
        }

        public String getMobile() {
            return mobile;
        }

        public void setMobile(String mobile) {
            this.mobile = mobile;
        }
    }

    /**
     * 签名字符串:84CBF6035C54EAFE62E3F57F1737C733
     * 参数json={"idNo":"463300122545556699","mobile":"19966667777","sign":"84CBF6035C54EAFE62E3F57F1737C733","userName":"张三"}
     * 验证签名是否一致=true
     * @param args
     */
    public static void main(String[] args) {
        try {
            String key = "testkey111";

            UserInfo userInfo = new UserInfo();
            userInfo.setMobile("19966667777");
            userInfo.setUserName("张三");
            userInfo.setIdNo("463300122545556699");
            String signStr = Signature.getSign(userInfo,key);
            System.out.println("签名字符串:" + signStr);
            userInfo.setSign(signStr);
            System.out.println("参数json=" + JSON.toJSONString(userInfo));

            //验证签名
            boolean flag = Signature.checkIsSignValidFromResyponseStringObject(userInfo,key);
            System.out.println("验证签名是否一致="+flag);

        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}
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;
    }
}