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進行比對,相等,則驗證成功。