zoukankan      html  css  js  c++  java
  • 第三方调用安全校验

    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 {
        }
    
        @Override
        public 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;
        }
    
        @Override
        public 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"));
        }
    
        @Override
        public BufferedReader getReader() throws IOException{
            InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(reqBytes));
            return new BufferedReader(isr);
        }
    
        @Override
        public 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;
    
                @Override
                public 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>
  • 相关阅读:
    51nod 1087 1 10 100 1000(找规律+递推+stl)
    51nod 1082 与7无关的数 (打表预处理)
    51 nod 1080 两个数的平方和
    1015 水仙花数(水题)
    51 nod 1003 阶乘后面0的数量
    51nod 1002 数塔取数问题
    51 nod 1001 数组中和等于K的数对
    51 nod 1081 子段求和
    51nod 1134 最长递增子序列 (O(nlogn)算法)
    51nod 1174 区间中最大的数(RMQ)
  • 原文地址:https://www.cnblogs.com/Jtianlin/p/7922732.html
Copyright © 2011-2022 走看看