签名工具类
签名规则:
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];
}
}