xiaoyong931011
2023-10-27 107c4d630c5b5c1b04f0d63a147e363b68dd1e8c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package cc.mrbird.febs.pay.util;
 
import cc.mrbird.febs.common.exception.JPException;
import cc.mrbird.febs.pay.model.Request;
import cc.mrbird.febs.pay.model.Response;
import cc.mrbird.febs.pay.model.SignTypeEnum;
import cn.hutool.core.util.ObjectUtil;
import com.alipay.service.schema.util.StringUtil;
 
import java.lang.reflect.Field;
import java.util.*;
 
/**
 * 签名、验签的工具类
 * @author chenyf
 * @date 2018-12-15
 */
public class SignUtil {
    public final static String SIGN_SEPARATOR = "&";//分隔符
    public final static String SIGN_EQUAL = "=";//等于号
    public final static String SIGN_KEY_PARAM_NAME = "key";
    public final static List<String> NOT_SIGN_PARAM = Arrays.asList(new String[]{"sign","aesKey","aes_key","sec_key"});//不参与签名/验签的参数
 
    /**
     * 验证签名
     * @param response
     * @param key
     * @return
     */
    public static boolean verify(Response response, String key) throws Exception {
        String signStr = getSortedString(response);
        if(SignTypeEnum.MD5.getValue().equals(response.getSign_type())){
            signStr = HEXUtil.encode(genMD5Sign(signStr, key), true);
            if(signStr.equals(response.getSign())){
                return true;
            }else{
                return false;
            }
        }else if(SignTypeEnum.RSA.getValue().equals(response.getSign_type())){
            return RSAUtil.verify(signStr, key, HEXUtil.decode(response.getSign()), true);
        }else{
            return false;
        }
    }
 
    /**
     * 生成签名
     * @param request
     * @param key
     * @return
     */
    public static void sign(Request request, String key) throws Exception {
        if(ObjectUtil.isEmpty(request)){
            return;
        }else if(StringUtil.isEmpty(request.getMch_id()) || StringUtil.isEmpty(request.getSign_type())){
            request.setSign("");
            return;
        }
 
        if(StringUtil.isEmpty(request.getRand_str())){
            request.setRand_str(RandomUtil.get32LenStr());
        }
 
        String signStr = getSortedString(request);
 
        if(SignTypeEnum.MD5.getValue().equals(request.getSign_type())){
            signStr = HEXUtil.encode(genMD5Sign(signStr, key), true);
        }else if(SignTypeEnum.RSA.getValue().equals(request.getSign_type())){
            signStr = HEXUtil.encode(RSAUtil.sign(signStr, key, true));
        }else{
            //抛出签名失败的异常
            throw new JPException("签名失败,未预期的签名类型:"+request.getSign_type());
        }
        request.setSign(signStr);
    }
 
    protected static String getSortedString(Object obj) throws Exception {
        Field[] fields = obj.getClass().getDeclaredFields();
 
        Map<String, String> map = new HashMap<String, String>();
        for(int i=0; i<fields.length; i++){
            Field filed = fields[i];
            String name = filed.getName();
            if(NOT_SIGN_PARAM.contains(name)){//不参与签名或验签的参数直接跳过
                continue;
            }
            filed.setAccessible(true);
            map.put(name, String.valueOf(filed.get(obj)));
        }
 
        StringBuffer content = new StringBuffer();
        List<String> keys = new ArrayList(map.keySet());
        Collections.sort(keys); // 排序map
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = map.get(key);
 
            if(i != 0){
                content.append(SIGN_SEPARATOR);
            }
            content.append(key).append(SIGN_EQUAL).append(value);
        }
        return content.toString();
    }
 
    private static byte[] genMD5Sign(String signStr, String key){
        return MD5Util.getMD5(signStr + SIGN_SEPARATOR + SIGN_KEY_PARAM_NAME + SIGN_EQUAL + key);
    }
}