今天想要手动的实现以下Filter权限控制,但是发现使用springboot的filter和之前的不一样,之前使用Servlet3.0只需要使用@WebFilter注解或者在web.xml文件中配置以下即可。但是springboot中没有web.xml文件,于是我很自然的使用注解,然后发现怎么也配置不上去,那么怎么办呢,没错,查文档。
经过一番查阅,原来spring中提供了三个注册器:FilterRegistrationBean、ServletRegistrationBean、ListenerRegistrationBean,分别用来配置Filter、Servlet和Listener,那么知道怎么回事了,下面先写一个Filter
1package xin.sun.filter; 2 3import javax.servlet.FilterChain; 4import javax.servlet.ServletException; 5import javax.servlet.http.HttpServletRequest; 6import javax.servlet.http.HttpServletResponse; 7import javax.servlet.http.HttpSession; 8import java.io.IOException; 9import java.util.Arrays; 10import java.util.List; 11 12/** 13 * Created by sun on 2017/8/4. 14 */ 15 16public class LoginFilter extends HttpFilter{ 17 18 /** 19 * ajax请求头key 20 */ 21 public static final String AJAX_HEAD_KEY = "x-requested-with"; 22 23 /** 24 * ajax请求头值 25 */ 26 public static final String AJAX_HEAD_VALUES = "XMLHttpRequest"; 27 28 private String uncheckedUrl; 29 private String sessionKey; 30 31 @Override 32 public void doFilter(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 33 34 HttpSession session = servletRequest.getSession(); 35 36 List<String> urls = Arrays.asList(uncheckedUrl.split(",")); 37 String servletPath = servletRequest.getServletPath(); 38 //不需要过滤的URL直接放行 39 if(urls.contains(servletPath)){ 40 filterChain.doFilter(servletRequest, servletResponse); 41 return; 42 } 43 44 String username = (String) session.getAttribute(sessionKey); 45 if (username == null || "".equals(username)) { 46 47 //判断Ajax请求 48 String reqMethod = servletRequest.getHeader(AJAX_HEAD_KEY); 49 if (AJAX_HEAD_VALUES.equalsIgnoreCase(reqMethod)) { 50 servletResponse.setHeader("sessionstatus","timeout"); 51 servletResponse.sendError(518, "session timeout."); 52 filterChain.doFilter(servletRequest, servletResponse); 53 return ; 54 } 55 56 //非ajax请求 57 servletResponse.setHeader("Cache-Control", "no-store"); 58 servletResponse.setDateHeader("Expires", 0); 59 servletResponse.setHeader("Prama", "no-cache"); 60 61 //获取绝对路劲的根路径 62 String basePath = servletRequest.getScheme()+"://"+servletRequest.getServerName()+":"+ 63 servletRequest.getServerPort()+servletRequest.getContextPath(); 64 65 //重定向到登录页面 66 servletResponse.sendRedirect(basePath+"/login"); 67 return; 68 } 69 70 filterChain.doFilter(servletRequest,servletResponse); 71 } 72 73 /** 74 * 初始化,获取初始化参数 75 */ 76 public void init(){ 77 uncheckedUrl = getFilterConfig().getInitParameter("uncheckedUrl"); 78 sessionKey = getFilterConfig().getInitParameter("sessionKey"); 79 } 80}
其实很多人在拦截的时候没有拦截ajax请求,那么会导致一个什么问题呢?当你的session超时后,你在页面中还可以发送ajax请求,是不是很荒唐,没错filter拦截ajax请求是需要做判断的,上面也给出了代码。
这个HttpFilter是我仿照HttpServlet写的,还是很实用的,我也贴出来一份
1package xin.sun.filter; 2 3import javax.servlet.*; 4import javax.servlet.FilterConfig; 5import javax.servlet.http.HttpServletRequest; 6import javax.servlet.http.HttpServletResponse; 7import java.io.IOException; 8 9/** 10 * Created by sun on 2017/8/4. 11 * 仿照HttpServlert,自定义HttpFilter,简化开发, 12 */ 13public abstract class HttpFilter implements Filter { 14 15 private FilterConfig filterConfig; 16 17 @Override 18 public void init(FilterConfig filterConfig) throws ServletException { 19 this.filterConfig = filterConfig; 20 this.init(); 21 } 22 23 /** 24 * 获取过滤器配置对象 25 * @return 26 */ 27 public FilterConfig getFilterConfig(){ 28 return this.filterConfig; 29 } 30 31 /** 32 * 获取初始化参数 33 * @param key 34 * @return 35 */ 36 public String getInitParameter(String key){ 37 return getFilterConfig().getInitParameter(key); 38 } 39 40 /** 41 * 获取应用上下文 42 * @return 43 */ 44 public ServletContext getServletContext() { 45 return this.getFilterConfig().getServletContext(); 46 } 47 48 /** 49 * 提供用户初始化方法 50 * @throws ServletException 51 */ 52 public void init() throws ServletException { 53 } 54 55 /** 56 * 重写doFilter(),把Servlert***转换为HttpServlert*** 57 * @param servletRequest 58 * @param servletResponse 59 * @param filterChain 60 * @throws IOException 61 * @throws ServletException 62 */ 63 @Override 64 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 65 HttpServletRequest request; 66 HttpServletResponse response; 67 try { 68 request = (HttpServletRequest)servletRequest; 69 response = (HttpServletResponse)servletResponse; 70 } catch (ClassCastException var6) { 71 throw new ServletException("non-HTTP request or response"); 72 } 73 this.doFilter(request,response,filterChain); 74 } 75 76 /** 77 * 提供一个doFilter()方法,用户必须实现 78 * @param servletRequest 79 * @param servletResponse 80 * @param filterChain 81 * @throws IOException 82 * @throws ServletException 83 */ 84 public abstract void doFilter(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException ; 85 86 @Override 87 public void destroy() { 88 89 } 90}
好了,重头戏来了,在springboot中配置这个filter
1package xin.sun.filter; 2 3import org.springframework.boot.web.servlet.FilterRegistrationBean; 4import org.springframework.context.annotation.Bean; 5import org.springframework.context.annotation.Configuration; 6 7/** 8 * Created by sun on 2017/8/4. 9 * 该类用于注册Filter 10 */ 11 12@Configuration 13public class FilterConfig { 14 15 @Bean 16 public FilterRegistrationBean loginFilterRegistration(){ 17 18 FilterRegistrationBean registration = new FilterRegistrationBean(); 19 20 //注入过滤器 21 registration.setFilter(new LoginFilter()); 22 23 //拦截规则 24 registration.addUrlPatterns("/*"); 25 26 //初始化参数 27 registration.addInitParameter("uncheckedUrl","/login,/registry,/loginServlet"); 28 registration.addInitParameter("sessionKey","SESSIONKEY"); 29 30 //过滤器名称 31 registration.setName("loginFilter"); 32 33 //是否自动注册 ,false 取消Filter的自动注册 34 registration.setEnabled(true); 35 36 //过滤器顺序 37 registration.setOrder(10); 38 39 return registration; 40 } 41 42 43}
那么Servlet其实原理是一样的,只是配置上略有不同罢了,自己去体会一下,这里就只给出代码了
1package xin.sun.servlet; 2 3import javax.servlet.ServletException; 4import javax.servlet.http.HttpServlet; 5import javax.servlet.http.HttpServletRequest; 6import javax.servlet.http.HttpServletResponse; 7import java.io.IOException; 8 9/** 10 * Created by sun on 2017/8/4. 11 */ 12public class LoginServlet extends HttpServlet { 13 14 @Override 15 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 16 17 //获取绝对路劲的根路径 18 String basePath = req.getScheme()+"://"+req.getServerName()+":"+ 19 req.getServerPort()+req.getContextPath(); 20 String username = req.getParameter("username"); 21 String password = req.getParameter("password"); 22 if(username.equals("admin")&&password.equals("123456")){ 23 req.getSession().setAttribute("SESSIONKEY",username); 24 resp.sendRedirect(basePath + "/indexPage"); 25 }else { 26 resp.sendRedirect(basePath + "/login"); 27 } 28 } 29 30 @Override 31 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 32 this.doGet(req, resp); 33 } 34} 35 36 37package xin.sun.servlet; 38 39import org.springframework.boot.web.servlet.ServletRegistrationBean; 40import org.springframework.context.annotation.Bean; 41import org.springframework.context.annotation.Configuration; 42 43import java.util.ArrayList; 44import java.util.HashMap; 45import java.util.List; 46import java.util.Map; 47 48/** 49 * Created by sun on 2017/8/4. 50 */ 51 52@Configuration 53public class ServletConfig { 54 55 @Bean 56 public ServletRegistrationBean loginServletRegistration(){ 57 ServletRegistrationBean registration = new ServletRegistrationBean(); 58 59 //设置servlet 60 registration.setServlet(new LoginServlet()); 61 62 //是否自动注册 ,false 取消Filter的自动注册 63 registration.setEnabled(true); 64 65 //设置URL映射地址 66 List urlMapping = new ArrayList<String>(); 67 urlMapping.add("/loginServlet"); 68 registration.setUrlMappings(urlMapping); 69 70 //设置加载就启动 71 registration.setLoadOnStartup(1); 72 73 //设置初始化参数 74 Map initParams = new HashMap<String, String>(); 75 initParams.put("key1","value1"); 76 registration.setInitParameters(initParams); 77 78 return registration; 79 } 80 81}
那么Listener也是一样的操作,照葫芦画瓢,留给大家去试试吧