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~

posted @ 2017-06-22 10:28 lichmama 阅读(...) 评论(...) 编辑 收藏