• javaweb利用filter拦截未授权请求


    项目上有个小需求,要限制访问者的IP,屏蔽未授权的请求。该场景使用过滤器来做再合适不过了。

    SecurityFilter.java:

    public class SecurityFilter implements Filter {
    
        private Log log = LogFactory.getLog(SecurityFilter.class);
        private List<String> whitelist = new ArrayList<String>();
        private List<String> regexlist = new ArrayList<String>();
        private static final String _JSON_CONTENT = "application/json; charset=UTF-8";
        private static final String _HTML_CONTENT = "text/html; charset=UTF-8";
        private static final String _403_JSON = "{'code': '403', 'msg': '访问被拒绝,客户端未授权!'}";
        private static final String _403_HTML = "<html><body><div style='text-align:center'><h1 style='margin-top: 10px;'>403 Forbidden!</h1><hr><span>@lichmama</span></div></body></html>";
    
        @Override
        public void destroy() {
        }
    
        @Override
        public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain)
                throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletrequest;
            HttpServletResponse response = (HttpServletResponse) servletresponse;
            if (isSecurityRequest(request)) {
                filterchain.doFilter(request, response);
            } else {
                log.info("拒绝来自[" + request.getRemoteAddr() + "]的访问请求:" + request.getRequestURI());
                response.setStatus(403);
                if (isAjaxRequest(request)) {
                    response.setContentType(_JSON_CONTENT);
                    response.getWriter().print(_403_JSON);
                } else {
                    response.setContentType(_HTML_CONTENT);
                    response.getWriter().print(_403_HTML);
                }
            }
        }
    
        @Override
        public void init(FilterConfig filterconfig) throws ServletException {
            String allowedIP = filterconfig.getInitParameter("allowedIP");
            if (allowedIP != null && allowedIP.length() > 0) {
                for (String item : allowedIP.split(",\s*")) {
                    // 支持通配符*
                    if (item.contains("*")) {
                        String regex = item.replace(".", "\.").replace("*", "\d{1,3}");
                        regexlist.add(regex);
                    } else {
                        whitelist.add(item);
                    }
                }
            }
        }
    
        /**
         * 判断当前请求是否来自可信任的地址
         * 
         * @param request
         * @return
         */
        private boolean isSecurityRequest(HttpServletRequest request) {
            String ip = request.getRemoteAddr();
            for (String item : whitelist) {
                if (ip.equals(item))
                    return true;
            }
            for (String item : regexlist) {
                if (ip.matches(item))
                    return true;
            }
            return false;
        }
    
        /**
         * 判断请求是否是AJAX请求
         * @param request
         * @return
         */
        private boolean isAjaxRequest(HttpServletRequest request) {
            String header = request.getHeader("X-Requested-With");
            if (header != null && header.length() > 0) {
                if ("XMLHttpRequest".equalsIgnoreCase(header))
                    return true;
            }
            return false;
        }
    }

    web.xml增加配置:

        <filter>  
            <filter-name>securityFilter</filter-name>  
            <filter-class>com.lichmama.webdemo.filter.SecurityFilter</filter-class>  
            <init-param>  
                <param-name>allowedIP</param-name>  
                <param-value>192.168.5.*</param-value>  
            </init-param>
        </filter>  
        
        <filter-mapping>  
            <filter-name>securityFilter</filter-name>  
            <url-pattern>/*</url-pattern>  
        </filter-mapping> 

      

    尝试访问,结果如下:

    *如何在Filter中获取Response的内容?这个问题之前还真没思考过,搜索了下得知如下方法可行:

    1.实现一个PrintWriterWrapper,用于替换ServletResponse中的Writer

    package com.lichmama.webdemo;
    
    import java.io.PrintWriter;
    import java.io.Writer;
    
    public class PrintWriterWrapper extends PrintWriter {
    
        private StringBuilder buff;
        
        public PrintWriterWrapper(Writer writer) {
            super(writer);
            buff = new StringBuilder();
        }
    
        @Override
        public void write(int i) {
            super.write(i);
            buff.append(i);
        }
    
        @Override
        public void write(char[] ac, int i, int j) {
            super.write(ac, i, j);
            buff.append(ac, i, j);
        }
    
        @Override
        public void write(char[] ac) {
            super.write(ac);
            buff.append(ac);
        }
    
        @Override
        public void write(String s, int i, int j) {
            super.write(s, i, j);
            buff.append(s, i, j);
        }
    
        @Override
        public void write(String s) {
            super.write(s);
            buff.append(s);
        }
        
        @Override
        public void flush() {
            super.flush();
            buff.delete(0, buff.length());
        }
    
        public String getContent() {
            return buff.toString();
        }
    }
    View Code

    2.实现一个ResponseWrapper,用于替换过滤链(FilterChain)中的ServletResponse:

    package com.lichmama.webdemo;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpServletResponseWrapper;
    
    public class ResponseWrapper extends HttpServletResponseWrapper {
    
        private PrintWriterWrapper writer;
        
        public ResponseWrapper(HttpServletResponse response) {
            super(response);
        }
    
        @Override
        public PrintWriter getWriter() throws IOException {
            if (writer == null)
                writer = new PrintWriterWrapper(super.getWriter());
            return writer;
        }
    
    }
    View Code

    3.编写Filter实现获取Response的内容捕获:

    package com.lichmama.webdemo.filter;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletResponse;
    
    import com.lichmama.webdemo.PrintWriterWrapper;
    import com.lichmama.webdemo.ResponseWrapper;
    
    public class TestFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterconfig) throws ServletException {
        }
    
        @Override
        public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain)
                throws IOException, ServletException {
            ResponseWrapper responsewrapper = new ResponseWrapper((HttpServletResponse) servletresponse);
            filterchain.doFilter(servletrequest, responsewrapper);
            PrintWriterWrapper writerWrapper = (PrintWriterWrapper) responsewrapper.getWriter();
            // TODO retrieve content from PrintWriterWrapper
            String content = writerWrapper.getContent();
        }
    
        @Override
        public void destroy() {
        }
    
    }

    that's it~

  • 相关阅读:
    微访谈之1:解答各位朋友关心的问题
    深入浅出SQL Server中的死锁(实战篇)
    怎样玩转千万级别的数据
    Another MySQL daemon already running with the same unix socket
    c++ undefined reference to mysqlinit
    Another MySQL daemon already running with the same unix socket
    linxu 挂载分区
    C# RSA
    谷歌地图实现车辆轨迹移动播放(google map api)
    百度地图实现车辆轨迹移动播放(baidu map api)
  • 原文地址:https://www.cnblogs.com/lichmama/p/7063587.html
Copyright © 2020-2023  润新知