登陆接口签名方案:
客户端在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 }