以前都是作后台逻辑,没怎么接触网关接口的代码。最近加入了跨境支付团队,团队大部分的工做就是对接商户,对接银行渠道,对接海关。因此写了不少的网关接口。写网关接口很单调,主要逻辑就是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; }