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