项目上有个小需求,要限制访问者的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(); } }
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; } }
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~