Java Servlet 过滤器登录注销会话示例教程

Java Servlet Filter 用于拦截客户端请求并做一些预处理。它还可以在将响应发送到 Web 应用程序中的客户端之前拦截响应并进行后处理。

小服务程序过滤器

在本文中,我们将学习 Java 中的 Servlet 过滤器。我们将研究 servlet 过滤器的各种用法,我们如何创建一个过滤器并通过一个简单的 Web 应用程序了解它的用法。

  1. 为什么我们有 Servlet 过滤器?

    在上一篇文章中,我们学习了如何在 Web 应用程序中管理会话,如果我们想确保只有在用户会话有效时才能访问资源,我们可以使用 servlet 会话属性来实现这一点。方法很简单,但是如果我们有很多 servlet 和 jsps,那么由于冗余代码,它会变得难以维护。如果我们以后想更改属性名称,我们将不得不更改我们进行会话身份验证的所有地方。

    这就是我们有一个 servlet 过滤器的原因。Servlet 过滤器是可插入的Java 组件,我们可以使用它们在请求发送到 servlet之前拦截和处理请求,并servlet 代码完成后以及容器将响应发送回客户端之前进行响应。

    我们可以使用 servlet 过滤器完成的一些常见任务是:

    • 将请求参数记录到日志文件。
    • 资源请求的认证和授权。
    • 在将请求正文或标头发送到 servlet 之前对其进行格式化。
    • 压缩发送给客户端的响应数据。
    • 通过添加一些 cookie、标头信息等来更改响应。

    正如我之前提到的,servlet 过滤器是可插入的,并在部署描述符 (web.xml) 文件中进行配置。Servlet 和过滤器彼此不知道,我们可以通过编辑 web.xml 添加或删除 servlet 过滤器。

    我们可以为单个资源设置多个过滤器,并且可以在 web.xml 中为单个资源创建一个过滤器链。我们可以通过实现javax.servlet.Filter接口来创建一个 Servlet 过滤器。

  2. Servlet 过滤器接口

    Servlet Filter 接口类似于 Servlet 接口,我们需要实现它来创建我们自己的 servlet 过滤器。Servlet 过滤器接口包含过滤器的生命周期方法,它由 servlet 容器管理。

    Servlet Filter 接口生命周期方法有:

    1. void init(FilterConfig paramFilterConfig) – 当容器初始化过滤器时,这是被调用的方法。这个方法在过滤器的生命周期中只被调用一次,我们应该在这个方法中初始化任何资源。容器使用FilterConfig向 Filter 提供初始化参数和 servlet 上下文对象。我们可以在这个方法中抛出 ServletException。
    2. doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain paramFilterChain) – 这是容器每次必须将过滤器应用于资源时调用的方法。容器提供请求和响应对象引用以过滤作为参数。FilterChain用于调用链中的下一个过滤器。这是责任链模式的一个很好的例子。
    3. void destroy() – 当容器卸载 Filter 实例时,它会调用 destroy() 方法。这是我们可以关闭过滤器打开的任何资源的方法。此方法在过滤器的生命周期内仅调用一次。
  3. Servlet WebFilter 注解

    javax.servlet.annotation.WebFilter在 Servlet 3.0 中引入,我们可以使用这个注解来声明一个 servlet 过滤器。我们可以使用此注解来定义初始化参数、过滤器名称和描述、servlet、url 模式和调度程序类型以应用过滤器。如果您经常更改过滤器配置,最好使用 web.xml,因为这不需要您重新编译过滤器类。

    阅读Java 注释教程

  4. web.xml 中的 Servlet 过滤器配置

    我们可以在 web.xml 中声明一个 servlet 过滤器,如下所示。

    
    <filter>
      <filter-name>RequestLoggingFilter</filter-name> <!-- mandatory -->
      <filter-class>com.journaldev.servlet.filters.RequestLoggingFilter</filter-class> <!-- mandatory -->
      <init-param> <!-- optional -->
      <param-name>test</param-name>
      <param-value>testValue</param-value>
      </init-param>
    </filter>
    

    我们可以将过滤器映射到 servlet 类或 url 模式,如下所示。

    
    <filter-mapping>
      <filter-name>RequestLoggingFilter</filter-name> <!-- mandatory -->
      <url-pattern>/*</url-pattern> <!-- either url-pattern or servlet-name is mandatory -->
      <servlet-name>LoginServlet</servlet-name>
      <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    

    注意:在为 servlet 创建过滤器链时,容器首先处理 url-patterns,然后是 servlet-names,因此如果您必须确保过滤器按特定顺序执行,请在定义过滤器映射时特别注意。

    Servlet 过滤器通常用于客户端请求,但有时我们也想使用RequestDispatcher来应用过滤器,在这种情况下我们可以使用调度程序元素,可能的值是 REQUEST、FORWARD、INCLUDE、ERROR 和 ASYNC。如果未定义分派器,则它仅应用于客户端请求。

  5. 用于记录和会话验证的 Servlet 过滤器示例

    在我们的servlet 过滤器示例中,我们将创建过滤器来记录请求 cookie 和参数,并验证除静态 HTML 和 LoginServlet 之外的所有资源的会话,因为它不会有会话。

    我们将创建一个动态 Web 项目ServletFilterExample,其项目结构如下图所示。

    login.html 是我们应用程序的入口点,用户将在其中提供登录 ID 和密码以进行身份​​验证。

    login.html 代码:

    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="US-ASCII">
    <title>Login Page</title>
    </head>
    <body>
    
    <form action="LoginServlet" method="post">
    
    Username: <input type="text" name="user">
    <br>
    Password: <input type="password" name="pwd">
    <br>
    <input type="submit" value="Login">
    </form>
    </body>
    </html>
    

    LoginServlet 用于验证来自客户端的登录请求。

    
    package com.journaldev.servlet.session;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    /**
     * Servlet implementation class LoginServlet
     */
    @WebServlet("/LoginServlet")
    public class LoginServlet extends HttpServlet {
    	private static final long serialVersionUID = 1L;
    	private final String userID = "admin";
    	private final String password = "password";
    
    	protected void doPost(HttpServletRequest request,
    			HttpServletResponse response) throws ServletException, IOException {
    
    		// get request parameters for userID and password
    		String user = request.getParameter("user");
    		String pwd = request.getParameter("pwd");
    		
    		if(userID.equals(user) && password.equals(pwd)){
    			HttpSession session = request.getSession();
    			session.setAttribute("user", "Pankaj");
    			//setting session to expiry in 30 mins
    			session.setMaxInactiveInterval(30*60);
    			Cookie userName = new Cookie("user", user);
    			userName.setMaxAge(30*60);
    			response.addCookie(userName);
    			response.sendRedirect("LoginSuccess.jsp");
    		}else{
    			RequestDispatcher rd = getServletContext().getRequestDispatcher("/login.html");
    			PrintWriter out= response.getWriter();
    			out.println("<font color=red>Either user name or password is wrong.</font>");
    			rd.include(request, response);
    		}
    
    	}
    
    }
    

    当客户端通过身份验证时,它被转发到 LoginSuccess.jsp

    LoginSuccess.jsp 代码:

    
    <%@ page language="java" contentType="text/html; charset=US-ASCII"
        pageEncoding="US-ASCII"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
    <title>Login Success Page</title>
    </head>
    <body>
    <%
    //allow access only if session exists
    String user = (String) session.getAttribute("user");
    String userName = null;
    String sessionID = null;
    Cookie[] cookies = request.getCookies();
    if(cookies !=null){
    for(Cookie cookie : cookies){
    	if(cookie.getName().equals("user")) userName = cookie.getValue();
    	if(cookie.getName().equals("JSESSIONID")) sessionID = cookie.getValue();
    }
    }
    %>
    <h3>Hi <%=userName %>, Login successful. Your Session ID=<%=sessionID %></h3>
    <br>
    User=<%=user %>
    <br>
    <a href="CheckoutPage.jsp">Checkout Page</a>
    <form action="LogoutServlet" method="post">
    <input type="submit" value="Logout" >
    </form>
    </body>
    </html>
    

    请注意,上述 JSP 中没有会话验证逻辑。它包含指向另一个 JSP 页面 CheckoutPage.jsp 的链接。

    CheckoutPage.jsp 代码:

    
    <%@ page language="java" contentType="text/html; charset=US-ASCII"
        pageEncoding="US-ASCII"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
    <title>Login Success Page</title>
    </head>
    <body>
    <%
    String userName = null;
    String sessionID = null;
    Cookie[] cookies = request.getCookies();
    if(cookies !=null){
    for(Cookie cookie : cookies){
    	if(cookie.getName().equals("user")) userName = cookie.getValue();
    }
    }
    %>
    <h3>Hi <%=userName %>, do the checkout.</h3>
    <br>
    <form action="LogoutServlet" method="post">
    <input type="submit" value="Logout" >
    </form>
    </body>
    </html>
    

    当客户端单击任何 JSP 页面中的 Logout 按钮时,将调用 LogoutServlet。

    
    package com.journaldev.servlet.session;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    /**
     * Servlet implementation class LogoutServlet
     */
    @WebServlet("/LogoutServlet")
    public class LogoutServlet extends HttpServlet {
    	private static final long serialVersionUID = 1L;
           
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        	response.setContentType("text/html");
        	Cookie[] cookies = request.getCookies();
        	if(cookies != null){
        	for(Cookie cookie : cookies){
        		if(cookie.getName().equals("JSESSIONID")){
        			System.out.println("JSESSIONID="+cookie.getValue());
        			break;
        		}
        	}
        	}
        	//invalidate the session if exists
        	HttpSession session = request.getSession(false);
        	System.out.println("User="+session.getAttribute("user"));
        	if(session != null){
        		session.invalidate();
        	}
        	response.sendRedirect("login.html");
        }
    
    }
    

    现在我们将创建日志记录和身份验证 servlet 过滤器类。

    
    package com.journaldev.servlet.filters;
    
    import java.io.IOException;
    import java.util.Enumeration;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletRequest;
    
    /**
     * Servlet Filter implementation class RequestLoggingFilter
     */
    @WebFilter("/RequestLoggingFilter")
    public class RequestLoggingFilter implements Filter {
    
    	private ServletContext context;
    	
    	public void init(FilterConfig fConfig) throws ServletException {
    		this.context = fConfig.getServletContext();
    		this.context.log("RequestLoggingFilter initialized");
    	}
    
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		HttpServletRequest req = (HttpServletRequest) request;
    		Enumeration<String> params = req.getParameterNames();
    		while(params.hasMoreElements()){
    			String name = params.nextElement();
    			String value = request.getParameter(name);
    			this.context.log(req.getRemoteAddr() + "::Request Params::{"+name+"="+value+"}");
    		}
    		
    		Cookie[] cookies = req.getCookies();
    		if(cookies != null){
    			for(Cookie cookie : cookies){
    				this.context.log(req.getRemoteAddr() + "::Cookie::{"+cookie.getName()+","+cookie.getValue()+"}");
    			}
    		}
    		// pass the request along the filter chain
    		chain.doFilter(request, response);
    	}
    
    	public void destroy() {
    		//we can close resources here
    	}
    
    }
    
    
    package com.journaldev.servlet.filters;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletContext;
    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;
    
    @WebFilter("/AuthenticationFilter")
    public class AuthenticationFilter implements Filter {
    
    	private ServletContext context;
    	
    	public void init(FilterConfig fConfig) throws ServletException {
    		this.context = fConfig.getServletContext();
    		this.context.log("AuthenticationFilter initialized");
    	}
    	
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    
    		HttpServletRequest req = (HttpServletRequest) request;
    		HttpServletResponse res = (HttpServletResponse) response;
    		
    		String uri = req.getRequestURI();
    		this.context.log("Requested Resource::"+uri);
    		
    		HttpSession session = req.getSession(false);
    		
    		if(session == null && !(uri.endsWith("html") || uri.endsWith("LoginServlet"))){
    			this.context.log("Unauthorized access request");
    			res.sendRedirect("login.html");
    		}else{
    			// pass the request along the filter chain
    			chain.doFilter(request, response);
    		}
    		
    		
    	}
    
    	public void destroy() {
    		//close any resources here
    	}
    
    }
    

    请注意,我们没有对任何 HTML 页面或 LoginServlet 进行身份验证。现在我们将在 web.xml 文件中配置这些过滤器映射。

    
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://java.sun.com/xml/ns/javaee" xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
      <display-name>ServletFilterExample</display-name>
      <welcome-file-list>
        <welcome-file>login.html</welcome-file>
      </welcome-file-list>
      
      <filter>
        <filter-name>RequestLoggingFilter</filter-name>
        <filter-class>com.journaldev.servlet.filters.RequestLoggingFilter</filter-class>
      </filter>
      <filter>
        <filter-name>AuthenticationFilter</filter-name>
        <filter-class>com.journaldev.servlet.filters.AuthenticationFilter</filter-class>
      </filter>
      
      <filter-mapping>
        <filter-name>RequestLoggingFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
      </filter-mapping>
      <filter-mapping>
        <filter-name>AuthenticationFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>
    </web-app>
    

    现在,当我们运行我们的应用程序时,我们将获得如下图所示的响应页面。

    如果您没有登录并尝试访问任何 JSP 页面,您将被转发到登录页面。

    在服务器日志文件中,您可以看到 servlet 过滤器以及 servlet 写入的日志。

    
    Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A}
    Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log
    INFO: Requested Resource::/ServletFilterExample/
    Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log
    INFO: Unauthorized access request
    Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A}
    Aug 13, 2013 1:06:07 AM org.apache.catalina.core.ApplicationContext log
    INFO: Requested Resource::/ServletFilterExample/login.html
    Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Request Params::{pwd=password}
    Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Request Params::{user=admin}
    Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,B7275762B8D23121152B1270D6EB240A}
    Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
    INFO: Requested Resource::/ServletFilterExample/LoginServlet
    Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
    Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
    Aug 13, 2013 1:06:43 AM org.apache.catalina.core.ApplicationContext log
    INFO: Requested Resource::/ServletFilterExample/LoginSuccess.jsp
    Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
    Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
    Aug 13, 2013 1:06:52 AM org.apache.catalina.core.ApplicationContext log
    INFO: Requested Resource::/ServletFilterExample/CheckoutPage.jsp
    Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
    Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
    Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
    INFO: Requested Resource::/ServletFilterExample/LogoutServlet
    JSESSIONID=8BDF777933194EDCAC1D8F1B73633C56
    User=Pankaj
    Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
    Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
    Aug 13, 2013 1:07:00 AM org.apache.catalina.core.ApplicationContext log
    INFO: Requested Resource::/ServletFilterExample/login.html
    Aug 13, 2013 1:07:06 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
    Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
    Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
    INFO: Requested Resource::/ServletFilterExample/LoginSuccess.jsp
    Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
    INFO: Unauthorized access request
    Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{JSESSIONID,8BDF777933194EDCAC1D8F1B73633C56}
    Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
    INFO: 0:0:0:0:0:0:0:1%0::Cookie::{user,admin}
    Aug 13, 2013 1:07:07 AM org.apache.catalina.core.ApplicationContext log
    INFO: Requested Resource::/ServletFilterExample/login.html
    

这就是java中的Servlet过滤器的全部内容。它是 Java EE Web 应用程序的重要特性之一,我们应该将它用于各种 servlet 执行的常见任务。在以后的文章中,我们将研究 servlet 侦听器和 cookie。

更新:在收到大量可下载项目的请求后,我已将其附加到帖子中,从下面的链接下载。

查看有关Servlet 侦听器的系列中的下一篇文章。

更新

Struts 2 使用 Servlet Filter 来拦截客户端请求并将它们转发到适当的操作类,这些被称为 Struts 2 拦截器。查看Struts 2 初学者教程。[no_toc]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值