guoshilong
2023-08-09 34c2f71c21bc56b359b27ad92061477a0ff3ff48
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package cn.gistack.system.user.sync.util;
 
import java.util.*;
 
/**
 * 计算签名工具类;
 * 签名计算方法为:
 *
 * sign = MD5(自然排序(排除签名的所有参数) + [requestPath] + [requestMethod[POST|GET]] + secretKey);
 * 注意 requestMethod 已经经过大写转换处理;
 */
public class SignBuilder {
    public final static String TIMESTAMP_KEY = "timestamp";
    public final static String CLIENT_ID_KEY = "clientId";
    public final static String SIGN_KEY = "sign";
    public final static String SALT_KEY = "salt";
 
    private final String clientId;
    private final String clientSecret;
 
    private Long timestamp;
 
    private String salt;
 
    private String requestPath;
    private String requestMethod;
 
    private String sign;
 
    private final Map<String, Object> allParam = new TreeMap<String, Object>();
 
 
    private SignBuilder(String clientId, String clientSecret) {
        this.clientId = clientId;
        this.clientSecret = clientSecret;
    }
 
 
    public static SignBuilder create(String clientId, String clientSecret) {
        return new SignBuilder(clientId, clientSecret);
    }
 
    /**
     * 构建实例的时候 自动生成时间戳,通过 SignBuilder.getTimestamp() 获取时间戳
     * @param clientId OAuth2.0中客户端ID 也称为 appId
     * @param clientSecret OAuth2.0中客户端秘钥 也称为 appSecret
     */
    public static SignBuilder createWithTimestampAndSalt(String clientId, String clientSecret) {
        SignBuilder result = new SignBuilder(clientId, clientSecret);
        return result.timestamp(System.currentTimeMillis()).salt();
    }
 
 
    public SignBuilder param(String key, Object value) {
        if (sign != null) {
            throw new RuntimeException("sign has been generated, can't change the param");
        }
 
        if (SIGN_KEY.equals(key)) {
            return this;
        }
 
        if (TIMESTAMP_KEY.equals(key)) {
            this.timestamp = Long.valueOf(String.valueOf(value));
        }
 
        if (SALT_KEY.equals(key)) {
            this.salt = String.valueOf(value);
        }
 
        allParam.put(key, value);
        return this;
    }
 
    public SignBuilder params(Map<String, Object> params) {
        if (params == null) {
            return this;
        }
 
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            param(entry.getKey(), entry.getValue());
        }
        return this;
    }
 
    /**
     * 设置时间戳
     * @param timestamp 时间戳
     */
    public SignBuilder timestamp(Long timestamp) {
        param(TIMESTAMP_KEY, timestamp);
        return this;
    }
 
    public SignBuilder requestPath(String requestPath) {
        if (sign != null) {
            throw new RuntimeException("sign has been generated, can't change the param");
        }
        this.requestPath = requestPath;
        return this;
    }
 
    public SignBuilder requestMethod(String requestMethod) {
        if (sign != null) {
            throw new RuntimeException("sign has been generated, can't change the param");
        }
        if (requestMethod != null) {
            this.requestMethod = requestMethod.toUpperCase();
        }
        return this;
    }
 
    public SignBuilder salt() {
        return salt(Math.random());
    }
 
    public SignBuilder salt(Object salt) {
        param(SALT_KEY, salt);
        return this;
    }
 
    /**
     * 获取 http 请求参数
     */
    public Map<String, Object> getQueryParamMap() {
        Map<String, Object> result = new HashMap<String, Object>(allParam);
        result.put(SIGN_KEY, sign());
        return result;
    }
 
    /**
     * debug使用,获取签名前的原文;<br>
     * 秘钥已脱敏,使用 <code>{clientSecret}</code> 代替
     */
    public String getRawDataBeforeSign() {
        return rawDataBeforeSign() + "{clientSecret}";
    }
 
 
    private String rawDataBeforeSign() {
        allParam.put(CLIENT_ID_KEY, clientId);
 
        if (timestamp != null && !allParam.containsKey(TIMESTAMP_KEY)) {
            allParam.put(TIMESTAMP_KEY, timestamp);
        }
 
        StringBuilder sb = new StringBuilder();
        for (Object value : allParam.values()) {
            if (value != null) {
                sb.append(String.valueOf(value).trim());
            }
        }
        if (requestPath != null) {
            sb.append(requestPath);
        }
 
        if (requestMethod != null) {
            sb.append(requestMethod.toUpperCase());
        }
 
        return sb.toString();
    }
 
    /**
     * 计算当前参数的签名,已经计算签名后,所有参数不可更改
     */
    public String sign() {
        if (sign != null) {
            return sign;
        }
 
        this.sign = MD5Util.getMD5String(rawDataBeforeSign() + clientSecret);
        if (this.sign == null) {
            return "";
        }
        return this.sign.toUpperCase();
    }
 
    public String getSalt() {
        return salt;
    }
 
    public String getClientId() {
        return clientId;
    }
 
    public Long getTimestamp() {
        return timestamp;
    }
}