JAVA 参数签名工具类


  签名工具类

  签名规则:
  MD5加密时,所有**参数名称**加密前必须**转小写**,根据参数名称**升序排列**后进行拼接,
  最后加上MD5key然后进行加密(MD5Key)
   例如:
     参数a = 111
     参数b = 222  
     参数c = 333
     根据参数名称排序后得到:a=111&b=222&c=333,最后追加md5key参数后得到待加密字符串       如下:
     sign = MD5(a=111&b=222&c=333&md5key=xxxxxx)
     生成的签名为32位并**转大写**
 

SignUtil.class

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 *  签名工具类
 *  MD5加密时,所有**参数名称**加密前必须**转小写**,根据参数名称**升序排列**后进行拼接,
 *  最后加上MD5key然后进行加密(MD5Key)
 *   例如:
 *      参数a = 111
 *      参数b = 222
 *      参数c = 333
 *      根据参数名称排序后得到:a=111&b=222&c=333,最后追加md5key参数后得到待加密字符串如下:
 *
 *      sign = MD5(a=111&b=222&c=333&md5key=xxxxxx)
 *
 *      生成的签名为32位并**转大写**
 *
 */
public class SignUtil {

    /**
     * 4、md5加密,得到32位签名**转大写**
    */
    public static String sign(JSONObject obj, String secret){
        if(obj == null || StringUtils.isBlank(secret)){
            return StringUtils.EMPTY;
        }
        String sign = MD5Util.md5Hex(getBaseString(obj, secret));
        return sign.toUpperCase();
    }

    /**
     * 3、根据排序结果,拼接参数值。并在最后面加上&md5key=(分配的加密key)
    */
    private static String getBaseString(JSONObject obj,String secret) {
        //移除含有的Sign参数
        if (obj.containsKey("sign")) {
            obj.remove("sign");
        }
        if (obj.containsKey("traceId")) {
            obj.remove("traceId");
        }
        Map<String, Object> sortMap = sortJSONObject(obj);
        List<String> paramList = new ArrayList<>();
        for (String key : sortMap.keySet()) {
            Object value = sortMap.get(key);
            if (value == null) {
                continue;
            }
            if (value instanceof Map || value instanceof List) {
                paramList.add(String.format("%s=%s", key, JSONObject.toJSONString(value)));
            } else {
                paramList.add(String.format("%s=%s", key, value.toString()));
            }
        }
        return String.join("&", paramList) + "&md5key="+secret;
    }

    /**
     * 1、请求参数名提取后,转小写
     *
     * 2、将小写的参数名按照字符串升序排序
    */
    private static LinkedHashMap<String, Object> sortJSONObject(JSONObject obj) {
        LinkedHashMap<String, Object> result = new LinkedHashMap<>();
        Set<String> keySet = obj.keySet().stream().sorted(Comparator.comparing(String::toLowerCase)).collect(Collectors.toCollection(LinkedHashSet::new));
        for (String key : keySet) {
            Object value = obj.get(key);
            if (value == null) {
                continue;
            }
            key = key.toLowerCase();
            if (value instanceof JSONObject) {
                result.put(key, sortJSONObject((JSONObject) value));
            }
            if (value instanceof JSONArray) {
                result.put(key, ((JSONArray) value).stream().map(o -> {
                    if (o instanceof JSONObject) {
                        return sortJSONObject((JSONObject) o);
                    }
                    return o;
                }).collect(Collectors.toList()));
            } else {
                result.put(key, value);
            }
        }
        return result;
    }

    public static void main(String[] args) {

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("sign","123456");
        jsonObject.put("a","1");
        jsonObject.put("b","2");
        jsonObject.put("c","3");

        DistributionSignUtil.sign(jsonObject,"OOO");

        String secret = "abcdefsign";
        JSONObject obj = new JSONObject();
        obj.put("id",1);
        obj.put("name","zhangsan");
        JSONObject train = new JSONObject();
        train.put("id","t1");
        train.put("name","G1");
        train.put("seat","S1");
        obj.put("train",train);

        List<JSONObject> tickets = new ArrayList<>();
        JSONObject ticket1 = new JSONObject();
        ticket1.put("id","ticket1");
        ticket1.put("name","ticket1");
        JSONObject ticket2 = new JSONObject();
        ticket2.put("id","ticket2");
        ticket2.put("name","ticket2");
        JSONObject ticket3 = new JSONObject();
        ticket3.put("id","ticket3");
        ticket3.put("name","ticket3");
        tickets.add(ticket1);
        tickets.add(ticket2);
        tickets.add(ticket3);
        obj.put("tickets",tickets);
        System.out.println(getBaseString(obj,secret));

    }

}
MD5Util.class


import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Hex;


import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class MD5Util {

    private static final String ALGORIGTHM_MD5 = "MD5";
    /**
     * <p>
     * 字符串生成MD5
     * </p>
     *
     * @param input
     * @param charset 编码(可选)
     * @return
     * @throws Exception
     */
    public static String createMD5CharSet(String input, String charset) throws Exception {
        byte[] data;
        if (charset != null && !"".equals(charset)) {
            data = input.getBytes(charset);
        } else {
            data = input.getBytes();
        }
        MessageDigest messageDigest = getMD5();
        messageDigest.update(data);
        return byteArrayToHexString(messageDigest.digest());
    }

    /**
     * <p>
     * 字符串生成MD5
     * </p>
     *
     * @param input
     * @param salt
     * @param charset 编码(可选)
     * @return
     * @throws Exception
     */
    public static String createMD5(String input, String salt, String charset) throws Exception {
        if (salt != null && !"".equals(salt)) {
            input += salt;
        }
        return createMD5CharSet(input, charset);
    }

    /**
     * <p>
     * MD5摘要字节数组转换为16进制字符串
     * </p>
     *
     * @param data MD5摘要
     * @return
     */
    private static String byteArrayToHexString(byte[] data) {
        // 用来将字节转换成 16 进制表示的字符
        char hexDigits[] = {
                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
        };
        // 每个字节用 16 进制表示的话,使用两个字符,所以表示成 16 进制需要 32 个字符
        char arr[] = new char[16 * 2];
        // 表示转换结果中对应的字符位置
        int k = 0;
        // 从第一个字节开始,对 MD5 的每一个字节转换成 16 进制字符的转换
        for (int i = 0; i < 16; i++) {
            // 取第 i 个字节
            byte b = data[i];
            // 取字节中高 4 位的数字转换, >>>为逻辑右移,将符号位一起右移
            arr[k++] = hexDigits[b >>> 4 & 0xf];
            // 取字节中低 4 位的数字转换
            arr[k++] = hexDigits[b & 0xf];
        }
        // 换后的结果转换为字符串
        return new String(arr);
    }

    /**
     * <p>
     * 获取MD5实例
     * </p>
     *
     * @return
     * @throws NoSuchAlgorithmException
     */
    private static MessageDigest getMD5() throws NoSuchAlgorithmException {
        return MessageDigest.getInstance(ALGORIGTHM_MD5);
    }

    public static String md5Hex(final String data) {
        return md5Hex(data, true, Charsets.UTF_8);
    }

    public static String md5Hex(final String data, final boolean toLowerCase, Charset charset) {
        return new String(Hex.encodeHex(md5(data, charset), toLowerCase));
    }

    private static byte[] md5(final String data, Charset charset) {
        return md5(data.getBytes(charset));
    }

    private static byte[] md5(final byte[] data) {
        return getDigest().digest(data);
    }

    static MessageDigest getDigest() {
        try {
            return MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 十六进制下数字到字符的映射数组
     */
    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};

    /**
     * 对字符串进行MD5编码
     *
     * @param originString
     * @return
     */
    public static String encodeByMD5(String originString) {
        if (originString != null) {
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                byte[] results = md.digest(originString.getBytes());
                String resultString = byteArrayToHexStringFor(results);
                return resultString.toUpperCase();
            } catch (Exception e) {
               e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 转换字节数组为16进制字串
     *
     * @param b 字节数组
     * @return 十六进制字串
     */
    private static String byteArrayToHexStringFor(byte[] b) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            resultSb.append(byteToHexString(b[i]));
        }
        return resultSb.toString();
    }


    /**
     * 将一个字节转化成16进制形式的字符串
     *
     * @param b
     * @return
     */
    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];
    }


}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值