1.签名验证的工具类:
签名规则:
- 将所有请求参数转成JSON字符串。
- 将请求密钥分别添加到上述JSON字符串的头部和尾部,格式如下:
secret请求参数JSON字符串secret。
3. 对该字符串进行MD5(签名)运算,得到一个二进制数组。
4. 将该二进制数组转换为一个十六进制的字符串,该字符串是这些请求参数的签名。
1 /** 2 * 请求参数签名工具类 3 * 4 */ 5 public class ParamSignUtils { 6 7 public static void main(String[] args) { 8 HashMap<String, String> signMap = new HashMap<String, String>(); 9 String secret = "ywwXMYoWoS63u26fB1r4U"; 10 HashMap SignHashMap = ParamSignUtils.sign(signMap, secret); 11 System.out.println("SignHashMap:" + SignHashMap); 12 List<String> ignoreParamNames = new ArrayList<String>(); 13 ignoreParamNames.add("a"); 14 HashMap SignHashMap2 = ParamSignUtils.sign(signMap, ignoreParamNames, secret); 15 System.out.println("SignHashMap2:" + SignHashMap2); 16 } 17 18 public static HashMap<String, String> sign(Map<String, String> paramValues, String secret) { 19 return sign(paramValues, null, secret); 20 } 21 22 /** 23 * @param paramValues 24 * @param ignoreParamNames 25 * @param secret 26 * @return 27 */ 28 public static HashMap<String, String> sign(Map<String, String> paramValues, List<String> ignoreParamNames, 29 String secret) { 30 try { 31 HashMap<String, String> signMap = new HashMap<String, String>(); 32 StringBuilder sb = new StringBuilder(); 33 List<String> paramNames = new ArrayList<String>(paramValues.size()); 34 paramNames.addAll(paramValues.keySet()); 35 if (ignoreParamNames != null && ignoreParamNames.size() > 0) { 36 for (String ignoreParamName : ignoreParamNames) { 37 paramNames.remove(ignoreParamName); 38 } 39 } 40 Collections.sort(paramNames); 41 sb.append(secret); 42 for (String paramName : paramNames) { 43 sb.append(paramName).append(paramValues.get(paramName)); 44 } 45 sb.append(secret); 46 byte[] md5Digest = getMD5Digest(sb.toString()); 47 String sign = byte2hex(md5Digest); 48 signMap.put("appParam", sb.toString()); 49 signMap.put("appSign", sign); 50 return signMap; 51 } catch (IOException e) { 52 throw new RuntimeException("加密签名计算错误", e); 53 } 54 55 } 56 57 /** 58 * @param paramValues 59 * @param ignoreParamNames 60 * @param secret 61 * @return 62 */ 63 public static HashMap<String, String> sign(String paramValues, String secret) { 64 try { 65 HashMap<String, String> signMap = new HashMap<String, String>(); 66 StringBuilder sb = new StringBuilder(secret); 67 if(!StringUtils.isBlank(paramValues)){ 68 sb.append(paramValues); 69 } 70 sb.append(secret); 71 byte[] md5Digest = getMD5Digest(sb.toString()); 72 String sign = byte2hex(md5Digest); 73 signMap.put("appParam", sb.toString()); 74 signMap.put("appSign", sign); 75 return signMap; 76 } catch (IOException e) { 77 throw new RuntimeException("加密签名计算错误", e); 78 } 79 80 } 81 82 public static String utf8Encoding(String value, String sourceCharsetName) { 83 try { 84 return new String(value.getBytes(sourceCharsetName), "UTF-8"); 85 } catch (UnsupportedEncodingException e) { 86 throw new IllegalArgumentException(e); 87 } 88 } 89 90 private static byte[] getSHA1Digest(String data) throws IOException { 91 byte[] bytes = null; 92 try { 93 MessageDigest md = MessageDigest.getInstance("SHA-1"); 94 bytes = md.digest(data.getBytes("UTF-8")); 95 } catch (GeneralSecurityException gse) { 96 throw new IOException(gse); 97 } 98 return bytes; 99 } 100 101 private static byte[] getMD5Digest(String data) throws IOException { 102 byte[] bytes = null; 103 try { 104 MessageDigest md = MessageDigest.getInstance("MD5"); 105 bytes = md.digest(data.getBytes("UTF-8")); 106 } catch (GeneralSecurityException gse) { 107 throw new IOException(gse); 108 } 109 return bytes; 110 } 111 112 private static String byte2hex(byte[] bytes) { 113 StringBuilder sign = new StringBuilder(); 114 for (int i = 0; i < bytes.length; i++) { 115 String hex = Integer.toHexString(bytes[i] & 0xFF); 116 if (hex.length() == 1) { 117 sign.append("0"); 118 } 119 sign.append(hex.toUpperCase()); 120 } 121 return sign.toString(); 122 } 123 124 }
2.获取HttpServletRequest的原生JSON参数
1 //获取请求JSON字符串 2 private String getParams(HttpServletRequest req) { 3 String result = null; 4 try { 5 // 包装request的输入流 6 BufferedReader br = new BufferedReader( 7 new InputStreamReader((ServletInputStream) req.getInputStream(), "utf-8")); 8 // 缓冲字符 9 StringBuffer sb = new StringBuffer(""); 10 String line; 11 while ((line = br.readLine()) != null) { 12 sb.append(line); 13 } 14 br.close();// 关闭缓冲流 15 result = sb.toString();// 转换成字符 16 System.out.println("result = " + result); 17 } catch (Exception e) { 18 e.printStackTrace(); 19 } 20 return result; 21 }
3.接口的具体实现
1 @RequestMapping(value = "/getNoticeStockOutHeader", method = RequestMethod.POST) 2 @ResponseBody 3 public ResponseIntf getNoticeStockOutHeader(HttpServletRequest request, HttpServletResponse response) { 4 response.setHeader("Access-Control-Allow-Origin", "*");// 跨域访问 5 response.setCharacterEncoding("utf-8"); 6 ResponseIntf res = new ResponseIntf(); 7 try { 8 request.setCharacterEncoding("utf-8"); 9 String json = this.getParams(request).replaceAll("\s*", "");//去掉所有空格 10 String sign = request.getHeader("sign"); 11 if(StringUtils.isBlank(sign)){ 12 throw new SecurityException("接口签名不能为空!"); 13 } 14 if(!validateSign(json,sign)){ 15 throw new SecurityException("签名验证不通过!"); 16 } 17 Gson gson = new Gson(); 18 RequestIntf req = gson.fromJson(json, RequestIntf.class); 19 res.setResult(noticeStockOutService.getNoticeStockOutHeaderList(req)); 20 res.setSuccess(true); 21 res.setMessage("调用成功"); 22 } catch (IllegalArgumentException e) { 23 e.printStackTrace(); 24 logger.error(StringUtils.getStackTrace(e)); 25 res.setSuccess(false); 26 res.setMessage("参数不合法!错误信息:" + e.getMessage()); 27 } catch (SecurityException e) { 28 e.printStackTrace(); 29 logger.error(StringUtils.getStackTrace(e)); 30 res.setSuccess(false); 31 res.setMessage("安全异常:" + e.getMessage()); 32 } catch (AppException e) { 33 res.setSuccess(false); 34 res.setMessage(e.getMessage()); 35 } catch (Exception e) { 36 e.printStackTrace(); 37 logger.error(StringUtils.getStackTrace(e)); 38 res.setSuccess(false); 39 res.setMessage("其它异常:" + e.getMessage()); 40 } 41 return res; 42 }
4.接口采用MD5加密,直接获取原生的JSON字符串近行加密,与存放在request的header中的sign进行比对,相等,则验证成功。