第三方调用安全校验
1. 攔截器代碼
/*** @Description 添加請求是否合法驗證攔截器* @author 田林(lin.tian@mljr.com)* @date 2017年12月1日 下午4:20:38*/ @Component("signature") public class SignatureFilter implements Filter {private Logger logger = LoggerFactory.getLogger(SignatureFilter.class);@Value("${rsaKey}")private String rsaKey;public final static String JSON_PARAMS_TYPE="application/json";public final static String FORM_PARAMS_TYPE="application/x-www-form-urlencoded";@Override public void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {Map<String,String> singleValueMap = Maps.newHashMap();HttpServletRequest httpRequest=(HttpServletRequest)request;String password = httpRequest.getHeader("password");// 是否通過驗證boolean flag = false;//時間戳String timestamp = httpRequest.getHeader("timestamp");String serverPath = httpRequest.getServletPath();if("/".equals(serverPath)||serverPath.contains("/fe-che-union/static")){chain.doFilter(request,response);}else{HttpServletResponse httpResponse= (HttpServletResponse) response;String contentType = httpRequest.getContentType();if(!StringUtils.isEmpty(contentType)&&contentType.contains(JSON_PARAMS_TYPE)){//如果是json請求方式SignatureRequestWrapper requestWrapper = new SignatureRequestWrapper(httpRequest);String body = HttpHelper.getBodyString(requestWrapper);if (StringUtils.isEmpty(body)) {logger.error("非法請求, 無參數");OutWriterUtil.write(httpResponse, JSONObject.toJSONString(RespDTO.fail("無參數")));return;}Map<String, Object> parameters = JSONObject.parseObject(body);Set<String> keySet = parameters.keySet();for(String key:keySet){singleValueMap.put(key, JSONObject.toJSONString(parameters.get(key)));}request=requestWrapper;}else if(!StringUtils.isEmpty(contentType)&&contentType.contains(FORM_PARAMS_TYPE)){Map<String,String[]> parameterMap = request.getParameterMap();for(String key : parameterMap.keySet()){String[] valueArray = parameterMap.get(key);if(valueArray!=null&&valueArray.length>0){singleValueMap.put(key, valueArray[0]);}}} else {flag = true;}if(flag){chain.doFilter(request,response);}else{// 校驗參數合法性flag = SignatureUtils.checkSign(singleValueMap, rsaKey,password,timestamp);if(flag){chain.doFilter(request,response);}else{OutWriterUtil.write(httpResponse, JSONObject.toJSONString(RespDTO.fail("簽名錯誤必須存在")));return;}}}}private boolean checkSign(Map<String, Object> parameters) {Map<String, String> requestParams=new HashMap<>();SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");for (String key : parameters.keySet()) {String valueStr="";Object value = parameters.get(key);if (value ==null){continue;}if(BeanUtils.isSimpleValueType(value.getClass())){ //如果是簡單類型if(Date.class.isAssignableFrom(value.getClass())){//如果是時間類型valueStr = dateFormat.format(value);}else{valueStr=value.toString();}}else {//如果是復雜類型valueStr=JSONObject.toJSONString(value);}requestParams.put(key,valueStr);}return SignUtils.checkSign(requestParams,rsaKey);}private boolean checkParamIsExist(Map<String, Object> parameters, String... keys) {for (String key: keys) {if(parameters.get(key)==null){return false;}}return true;}@Overridepublic void destroy() {}}?
2. 對輸入流進行封裝:
public class SignatureRequestWrapper extends HttpServletRequestWrapper {private HttpServletRequest original;private byte[] reqBytes;private boolean firstTime = true;public SignatureRequestWrapper(HttpServletRequest request) {super(request);reqBytes = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));}@Overridepublic BufferedReader getReader() throws IOException{InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(reqBytes));return new BufferedReader(isr);}@Overridepublic ServletInputStream getInputStream() throws IOException {ServletInputStream sis = new ServletInputStream() {@Override public boolean isFinished() {return false;}@Override public boolean isReady() {return false;}@Override public void setReadListener(ReadListener readListener) {}private int i;@Overridepublic int read() throws IOException {byte b;if(reqBytes.length > i){b = reqBytes[i++];}else{b = -1;}return b;}};return sis;}}?
3. 校驗代碼
public class SignUtils {/*** 拼接鍵值對** @param key* @param value* @param isEncode* @return*/private static String buildKeyValue(String key, String value, boolean isEncode) {StringBuilder sb = new StringBuilder();sb.append(key);sb.append("=");if (isEncode) {try {sb.append(URLEncoder.encode(value, "UTF-8"));} catch (UnsupportedEncodingException e) {sb.append(value);}} else {sb.append(value);}return sb.toString();}/*** 對支付參數信息進行簽名** @param map* 待簽名授權信息** @return*/public static String sign(Map<String, String> map, String rsaKey) {StringBuilder sortStr = getSortStr(map);StringBuilder authInfo = getAuthInfo(rsaKey, sortStr);String sign = EncryptUtil.MD5(authInfo.toString());return sign;}private static StringBuilder getAuthInfo(String rsaKey, StringBuilder sortStr) {StringBuilder authInfo=new StringBuilder();authInfo.append(rsaKey);authInfo.append(sortStr);authInfo.append(rsaKey);return authInfo;}private static StringBuilder getSortStr(Map<String, String> map) {List<String> keys = new ArrayList<String>(map.keySet());// key排序 Collections.sort(keys);StringBuilder authInfo = new StringBuilder();for (int i = 0; i < keys.size() - 1; i++) {String key = keys.get(i);String value = map.get(key);authInfo.append(buildKeyValue(key, value, false));authInfo.append("&");}String tailKey = keys.get(keys.size() - 1);String tailValue = map.get(tailKey);authInfo.append(buildKeyValue(tailKey, tailValue, false));return authInfo;}/*** 要求外部訂單號必須唯一。* @return*/public static boolean checkSign(Map<String, String> map, String rsaKey) {String password=map.remove("password");StringBuilder sortStr = getSortStr(map);StringBuilder authInfo = getAuthInfo(rsaKey, sortStr);return EncryptUtil.checkPassWord(authInfo.toString(),password);}?
4. Filter 無法直接通過 @Value 注入properties屬性 ,可以通過?DelegatingFilterProxy 來處理,將Filter 交給spring來管理。web.xml 配置:
<filter><filter-name>signature</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class></filter><filter-mapping><filter-name>signature</filter-name><url-pattern>/*</url-pattern></filter-mapping>?
轉載于:https://www.cnblogs.com/Jtianlin/p/7922732.html
總結
- 上一篇: C#实现发送手机短信
- 下一篇: 理解矩阵与线性代数