登錄接口簽名方案:
客戶端在Header中傳遞時間戳("curTime")、入參的md5值("md5")和校驗和("checkSum")等3個參數;
(1)md5值:
客戶端將請求入參使用md5加密並轉成十六進制的字符串形式,放入Header;
(2)校驗和:
客戶端將APPSECRET(暫時寫死 "67wGmp7PdhwEp9I4"), md5, curTime等3個參數使用sha1加密並轉成十六進制的字符串形式,放入Header();
注意事項:
入參中的各項參數首字母必須按照字典排序,不能使用格式化後的json, 不然校驗不經過.
sha1密文示例:7c4a8d09ca3762af61e56520943dc26494f8941b
md5密文示例:e10adc3949ba56abbe56e057f20f883e
--------------------------------------------
測試手機號登錄接口示例[已測試經過]:
header部分:
curTime:1532152323277
md5:b580f998587cbfa05ab693581b750a3c
checkSum:485c555005e0664790ff69583cbcb75394f8d4ed
入參部分[注意json不要格式化]:
{"channelType":"9","checkKey":"123456","devId":"87cbfa05ab093581b75","equipmentType":"2","imageCode":"dh59Ds","phone":"13966672478","smsCode":"985264"}
若是簽名校驗失敗會返回:
{
"code": 200,
"errorCode": "549",
"errorMsg": "簽名驗證失敗",
"sid": "6d4a871da5094e4799f0e8cc0b1183461532153216096",
"success": true
}
--------------------------------------------
1 import com.alibaba.fastjson.JSON;
2 import com.alibaba.fastjson.serializer.SerializerFeature;
3 import org.springframework.util.StringUtils;
4
5 import java.security.MessageDigest;
6 import java.util.HashMap;
7 import java.util.Map;
8
9 /**
10 * 簽名工具
11 *
12 * @Author: syj
13 * @CreateDate: 2018/7/20 17:32
14 */
15 public class SignUtil {
16
17 /**
18 * APP密碼
19 */
20 private static final String QMALLL_LOGIN_APPSECRET = "DkkGmp3PdhwEp6I8";
21
22 /**
23 * 校驗簽名
24 *
25 * @param curTime 時間戳
26 * @param requestBody 請求參數
27 * @param md5 請求參數的md5值
28 * @param checkSum 校驗和(將appsecret、請求參數md5值和時間戳採用sha1加密)
29 * @return
30 */
31 private boolean doCheck(String curTime, String requestBody, String md5, String checkSum) {
32 if (StringUtils.isEmpty(md5) || StringUtils.isEmpty(checkSum)) {
33 return false;
34 }
35 String verifyMD5 = SignUtil.md5(requestBody);
36 String verifyChecksum = SignUtil.checkSum(QMALLL_LOGIN_APPSECRET, verifyMD5, curTime);
37 return md5.equals(verifyMD5) && checkSum.equals(verifyChecksum) ? true : false;
38 }
39
40 /**
41 * 計算並獲取CheckSum
42 * 使用sha1加密
43 *
44 * @param appSecret
45 * @param nonce
46 * @param curTime
47 * @return
48 */
49 public static String checkSum(String appSecret, String nonce, String curTime) {
50 return encode("sha1", appSecret + nonce + curTime);
51 }
52
53 /**
54 * 計算並獲取md5值
55 *
56 * @param requestBody
57 * @return
58 */
59 public static String md5(String requestBody) {
60 return encode("md5", requestBody);
61 }
62
63 public static String encode(String algorithm, String value) {
64 if (value == null) {
65 return null;
66 }
67 try {
68 MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
69 messageDigest.update(value.getBytes());
70 return getFormattedText(messageDigest.digest());
71 } catch (Exception e) {
72 throw new RuntimeException(e);
73 }
74 }
75
76 /**
77 * 把密文轉換成十六進制的字符串形式
78 *
79 * @param bytes
80 * @return
81 */
82 private static String getFormattedText(byte[] bytes) {
83 int len = bytes.length;
84 StringBuilder buf = new StringBuilder(len * 2);
85 for (int j = 0; j < len; j++) {
86 buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
87 buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
88 }
89 return buf.toString();
90 }
91
92 private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
93
94 /**
95 * 簽名測試
96 */
97 private static void signTest() {
98 // 請求時間戳
99 String curTime = String.valueOf(System.currentTimeMillis());
100
101 // 模擬請求入參
102 Map<String, Object> map = new HashMap<>();
103 map.put("userName", "admin");
104 map.put("password", "123456");
105 map.put("applicationId", 1L);
106 map.put("otherNickName", "系統管理員");
107 map.put("phone", "15801081566");
108 map.put("verificationCode", "123456");
109 map.put("responseType", "1");
110 map.put("osType", "ios");
111 map.put("mac", "123456789");
112 // 轉成json並按字典排序(注意版本:本人使用的fastjson版本爲1.2.47)
113 String requestBody = JSON.toJSONString(map, SerializerFeature.MapSortField);
114
115 // 對請求入參使用md5加密
116 String md5 = SignUtil.md5(requestBody);
117
118 // 使用sha1加密
119 String checkSum = SignUtil.checkSum(QMALLL_LOGIN_APPSECRET, md5, curTime);
120
121 // 校驗
122 signTest(curTime, requestBody, md5, checkSum);
123 }
124
125 /**
126 * 加密測試
127 */
128 private static void md5Test(String data) {
129 String sha1 = SignUtil.encode("sha1", data);
130 String md5 = SignUtil.encode("md5", data);
131 System.out.println("sha1密文:" + sha1);
132 System.out.println("md5密文:" + md5);
133 }
134
135 /**
136 * 測試簽名
137 *
138 * @param curTime 時間戳
139 * @param requestBody 請求參數
140 * @param md5 請求參數的md5值
141 * @param checkSum 校驗和(將appsecret、請求參數md5值和時間戳採用sha1加密)
142 * @return
143 */
144 public static boolean signTest(String curTime, String requestBody, String md5, String checkSum) {
145 System.out.println("入參:curTime=" + curTime);
146 System.out.println("入參:requestBody=" + requestBody);
147 System.out.println("入參:md5=" + md5);
148 System.out.println("入參:checkSum=" + checkSum);
149 // 計算md5
150 String verifyMD5 = SignUtil.md5(requestBody);
151 // 計算checkSum
152 String verifyChecksum = SignUtil.checkSum(QMALLL_LOGIN_APPSECRET, verifyMD5, curTime);
153
154 System.out.println("md5值:" + verifyMD5);
155 System.out.println("校驗和:" + verifyChecksum);
156
157 // 比較md5,checkSum是否一致
158 boolean checkResult = md5.equals(verifyMD5) && checkSum.equals(verifyChecksum) ? true : false;
159 System.out.println("校驗結果:" + checkResult);
160 return checkResult;
161 }
162
163 /**
164 * 測試
165 *
166 * @param args
167 */
168 public static void main(String[] args) {
169 md5Test("admin");
170 signTest();
171 }
172
173 }