以前都是作後臺邏輯,沒怎麼接觸網關接口的代碼。最近加入了跨境支付團隊,團隊大部分的工做就是對接商戶,對接銀行渠道,對接海關。因此寫了不少的網關接口。寫網關接口很單調,主要邏輯就是java
- 1.加簽-發送請求 - 2.1 處理同步響應:驗籤-處理內容-加簽響應-發送響應 - 2.2 處理異步響應:異步又分兩種。 - 2.2.1 在第一步時提供了回調接口。驗籤-處理內容-加簽響應-發送響應 - 2.2.2 經過第一步返回的一個號碼去作定時任務查詢。加簽-發送查詢-驗籤-處理響應內容。
能夠看見,在每一次發送請求時,都會加簽,在每次接到響應時,都會驗籤。數據庫
商戶在調用跨境系統的網關接口時,須要使用祕鑰加簽。加簽的做用有兩個1.防篡改 2.身份識別。咱們經過RSA或者MD5兩張方式來實現。
RSA是非對稱加密,商戶持有私鑰,用來加簽。跨境系統持有公鑰,用來驗籤。如商戶發送內容:明文+摘要(明文用私鑰加簽),系統接收驗證:摘要+公鑰=明文app
MD5是對稱的,只能作防篡改,咱們在計算摘要時將MD5值接到內容末尾,就能夠實現身份識別。商戶發送內容:明文+摘要(明文+MD5再用MD5散列),系統接收驗證(明文+MD5串再用MD5散列,看是否是和用戶傳過來摘要同樣)。異步
注意,明文在加簽時,須要排序,以便在商戶和跨境系統獲得統一的字符串。加密
在商戶後臺,容許商戶下載祕鑰(MD5,或是RSA),每次下載都會使得以前的祕鑰失效。若是是MD5,讓用戶下載一個包含MD5的文件,同時跨境系統也會將這個值更新到數據庫。若是是RSA,讓用戶下載一個包含公私鑰的文件,同時跨境系統將其中的公鑰更新到數據庫。code
以上是基本的實現方案。如下是一些相關的代碼排序
//讀取request中的值,如今我有兩個方法,還不清楚二者的區別。一個是經過讀流的方式,一個是經過getParameterMap的方式。 private Map<String, String> getParams(HttpServletRequest request){ Map<String, String> params = new HashMap<String, String>(); StringBuffer sb = new StringBuffer(); BufferedReader read = null; try{ read = new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8")); String line = null; while((line = read.readLine()) != null){ sb.append(line); } } catch (Exception e){ logger.info("讀取流異常"); } finally { try { if(read != null) read.close(); } catch (IOException e) { logger.info("IO關閉異常"); } } logger.info("notify返回值:" + sb.toString()); params = JSON.parseObject(sb.toString(), Map.class); return params; }
private Map<String,String> getParams(HttpServletRequest request){ Map<String, String> map = new HashMap<String,String>(); Enumeration enu=request.getParameterNames(); while(enu.hasMoreElements()){ String paraName=(String)enu.nextElement(); map.put(paraName,request.getParameter(paraName)); } return map; }
//request中參數排序,返回有序的明文字符串 public static String createLinkString(Map<String, String> map){ List<String> list = new ArrayList<String>(map.keySet()); Collections.sort(list); StringBuffer sb = new StringBuffer(); for(int i=0; i<list.size(); i++){ String key = list.get(i); String value = map.get(key); if(i == list.size() - 1){ sb.append(key).append("=").append(value); } else { sb.append(key).append("=").append(value).append("&"); } } return sb.toString(); }
//跨境網關驗籤 public boolean verifyBySignType(String src, String signMsg, String signType, String key, String charsetType) throws Exception { int charset = Integer.valueOf(charsetType).intValue(); CharsetTypeEnum charsetin = CharsetTypeEnum.getByCode(charset); if (SignTypeEnum.getByCode(signType) == null) { log.error("@FI-加簽類型不正確"); throw new ParamValidateException("FI-加簽類型不正確", ExceptionCodeEnum.ILLEGAL_PARAMETER); } if (charsetin == null) { log.error("@FI-字符集類型不正確"); throw new ParamValidateException("FI-字符集類型不正確", ExceptionCodeEnum.ILLEGAL_PARAMETER); } if (null != signType && signType.equals(SignTypeEnum.RSA.getCode())) {// RSA try { return SecuritySubstance.verifySignatureByRSA(src, signMsg, charsetin, key); } catch (Exception e) { log.error("RSA驗籤:驗簽過程異常" + e); throw new Exception(e); } } else if (null != signType && signType.equals(SignTypeEnum.MD5.getCode())) { try { return SecuritySubstance.verifySignatureByMD5(src, signMsg, charsetin, key); } catch (Exception e) { log.error("MD5驗籤:驗簽過程異常" , e); throw new Exception(e); } } return false; }
//MD5驗籤 /** * 校驗簽名MD5 * @param src 原數據 * @param dit 加簽後數據 * @return result */ public static boolean verifySignatureByMD5(String src, String dit, CharsetTypeEnum charsetType,String parnterPublicKey) throws Exception { src += pkeyHeader+parnterPublicKey; String mac = null; try{ mac = MD5BaseAlgorithms.getMD5Str(src); }catch(Exception e){ System.err.println("MD5 驗簽出現異常"); e.printStackTrace(); return false; } if(dit.equals(mac)){ return true; } return false; }
//RSA驗籤 /** * 校驗簽名RSA * @param src 原數據 * @param dit 加簽後數據 * @param publicKey Base64後的公鑰 * @return result */ public static boolean verifySignatureByRSA(String src, String dit, CharsetTypeEnum charsetType, String publicKey) throws Exception { boolean result = false; int hashCode = HashAlgorithms.PJWHash(src); String hashSrc = hashCode+""; RSAAlgorithms sign = new RSAAlgorithms(); try { result = sign.verifySignature(hashSrc.getBytes(), dit, ByteArrayUtil.toByteArray(publicKey)); } catch (Exception e) { System.err.println("RSA 驗簽出現異常"); e.printStackTrace(); result = false; } return result; }