最近在看过滤器,刚刚实现了过滤器的简化认证功能:
使用过滤器简化认证:
在Web应用程序中,过滤器的一个关键用例是保护应用程序不被未授权的用户访问。为跨国部件公司开发的客户支持应用程序使用了一种非常原始的认证机制保护页面。你可能已经注意到应用程序中的许多地方都包含了相同的重复代码,用于检查认证:
1 if (request.getSession().getAttribute("userName") == null){ 2 response.sendRedirect("login"); 3 return; 4 }
同时你可能认为认证更简单的方式就是在某个类上创建一个公开静态方法执行该检查,并在所有的地方调用它。确实,这将减少重复代码,但它仍然会导致在多个地方调用该方法的问题。随着应用程序中,Servlet数量的增加,同样也会增加对该静态方法的调用。
所以过滤器对简化认证还是很有用处的,我做了一个小小的demo,思路是,调用listServlet,listServlet中重定向到index.jsp,当然我在webListener中动态配置Filter的时候就是对路径"/index.jsp"页面配置的。所以在跳转到index.jsp页面之前,会执行过滤器中的代码(判断是否已经登录,登录状态允许跳转到index.jsp,非登录状态将重定向到login.jsp让用户登录).
接下来是listServlet(我直接进入这个servlet开启整个demo的测试)
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet(name="listServlet",urlPatterns="/list") public class listServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("listServet"); resp.sendRedirect(req.getServletContext().getContextPath() + "/index.jsp"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } }
这是对应的过滤器AuthenticationFilter
import java.io.IOException; import java.time.Instant; 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.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class AuthenticationFilter implements Filter{ @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {if (req.getAttribute("userName") == null) { ((HttpServletResponse)resp).sendRedirect(req.getServletContext().getContextPath() + "/login.jsp"); }else{ chain.doFilter(req, resp); } } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
在web监听器中,会配置相应的过滤器
1 package deep.web.listener; 2 3 import java.util.Collection; 4 5 import javax.servlet.FilterRegistration; 6 import javax.servlet.ServletContext; 7 import javax.servlet.ServletContextEvent; 8 import javax.servlet.ServletContextListener; 9 import javax.servlet.annotation.WebListener; 10 11 import deep.web.filter.AuthenticationFilter; 12 13 @WebListener 14 public class Configurator implements ServletContextListener{ 15 16 @Override 17 public void contextDestroyed(ServletContextEvent arg0) { 18 // TODO Auto-generated method stub 19 20 } 21 22 @Override 23 public void contextInitialized(ServletContextEvent event) { 24 ServletContext context = event.getServletContext(); 25 26 FilterRegistration.Dynamic registration = context.addFilter("authenticationFilter", new AuthenticationFilter()); 27 28 registration.setAsyncSupported(true); 29 System.out.println("contextInitialized"); 30 31 registration.addMappingForUrlPatterns(null, false, "/index.jsp"); 32 33 /*这是我测试用的,判断是否配置好了url,并且输出url*/ 34 System.out.println(registration.getUrlPatternMappings().isEmpty()); 35 Collection<String> str = registration.getUrlPatternMappings(); 36 System.out.println(str); 37 } 38 39 }
我把loginServlet也粘贴出来吧
1 package deep.web.controller; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletException; 6 import javax.servlet.annotation.WebServlet; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 12 @WebServlet(name="userServlet",urlPatterns="/user") 13 public class userServlet extends HttpServlet{ 14 private static final long serialVersionUID = 1L; 15 @Override 16 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 17 18 } 19 @Override 20 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 21 System.out.println("userServlet"); 22 String method= req.getParameter("method"); 23 if (method.equals("login")) { 24 System.out.println("loginServlet"); 25 String name = req.getParameter("name"); 26 String password = req.getParameter("password"); 27 if (name.equals("test") && password.equals("test")) { 28 req.getSession().setAttribute("userName","name" ); 29 resp.sendRedirect(req.getServletContext().getContextPath() + "/list.jsp"); 30 }else{ 31 System.out.println("登录失败~"); 32 resp.sendRedirect(req.getServletContext().getContextPath() + "/login.jsp"); 33 } 34 } 35 } 36 }
接下来是输出结果,我会直接进入listServlet→进入过滤器(如果已经登录)→进入index.jsp
→进入过滤器(如果没有登录)→进入login.jsp
采用这种方式的优势在于:如果要修改认证算法,只需要修改过滤器就可以保护应用程序中的资源。之前,你将不得不修改所有的Servlet。
其实不应该用request来认证,应该用session,额,脑瓜子疼...sorry
参考书籍:《Java Web高级编程》