Skip to content

Filter

Filter

Session 存储在浏览器, cookie存在服务器, Session 安全, cookie不安全

cookie是设置后每一次请求都会携带cookie信息, 该路径下每一个servlet都会根据该cookie响应, session是只有包含用户信息的才会响应.

有了Session之后,我们就可以很好地控制用户的登陆验证了,只有授权的用户,才可以访问一些页面,但是我们需要一个一个去进行配置,还是太过复杂,能否一次性地过滤掉没有登录验证的用户呢?

过滤器相当于在所有访问前加了一堵墙,来自浏览器的所有访问请求都会首先经过过滤器,只有过滤器允许通过的请求,才可以顺利地到达对应的Servlet,而过滤器不允许的通过的请求,我们可以自由地进行控制是否进行重定向或是请求转发。并且过滤器可以添加很多个,就相当于添加了很多堵墙,我们的请求只有穿过层层阻碍,才能与Servlet相拥,像极了爱情。

点击查看源网页

添加一个过滤器非常简单,只需要实现Filter接口,并添加@WebFilter注解即可:

@WebFilter("/*")   //路径的匹配规则和Servlet一致,这里表示匹配所有请求
public class TestFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

    }
}

Screenshot 2024-05-08 at 20.02.08

这样我们就成功地添加了一个过滤器,那么添加一句打印语句看看,是否所有的请求都会经过此过滤器:

HttpServletRequest request = (HttpServletRequest) servletRequest;
System.out.println(request.getRequestURL());

我们发现,现在我们发起的所有请求,一律需要经过此过滤器,并且所有的请求都没有任何的响应内容。

Screenshot 2024-05-08 at 20.06.49

Screenshot 2024-05-08 at 20.06.59

那么如何让请求可以顺利地到达对应的Servlet,也就是说怎么让这个请求顺利通过呢?我们只需要在最后添加一句:

filterChain.doFilter(servletRequest, servletResponse);

那么这行代码是什么意思呢?

Screenshot 2024-05-09 at 10.36.46

由于我们整个应用程序可能存在多个过滤器,那么这行代码的意思实际上是将此请求继续传递给下一个过滤器,当没有下一个过滤器时,才会到达对应的Servlet进行处理,我们可以再来创建一个过滤器看看效果:

@WebFilter("/*")
public class TestFilter2 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("我是2号过滤器");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

由于过滤器的过滤顺序是按照类名的自然排序进行的,因此我们将第一个过滤器命名进行调整。

Screenshot 2024-05-09 at 15.35.22

Screenshot 2024-05-09 at 15.35.35

我们发现,在经过第一个过滤器之后,会继续前往第二个过滤器,只有两个过滤器全部经过之后,才会到达我们的Servlet中。

点击查看源网页

实际上,当doFilter方法调用时,就会一直向下直到Servlet,在Servlet处理完成之后,又依次返回到最前面的Filter,类似于递归的结构,我们添加几个输出语句来判断一下:

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    System.out.println("我是2号过滤器");
    filterChain.doFilter(servletRequest, servletResponse);
    System.out.println("我是2号过滤器,处理后");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    System.out.println("我是1号过滤器");
    filterChain.doFilter(servletRequest, servletResponse);
    System.out.println("我是1号过滤器,处理后");
}

最后验证我们的结论。

Screenshot 2024-05-09 at 15.46.17

同Servlet一样,Filter也有对应的HttpFilter专用类,它针对HTTP请求进行了专门处理,因此我们可以直接使用HttpFilter来编写:

public abstract class HttpFilter extends GenericFilter {
    private static final long serialVersionUID = 7478463438252262094L;

    public HttpFilter() {
    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
            this.doFilter((HttpServletRequest)req, (HttpServletResponse)res, chain);
        } else {
            throw new ServletException("non-HTTP request or response");
        }
    }

    protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
        chain.doFilter(req, res);
    }
}

那么现在,我们就可以给我们的应用程序添加一个过滤器,用户在未登录情况下,只允许静态资源和登陆页面请求通过,登陆之后畅行无阻:

@WebFilter("/*")
public class MainFilter extends HttpFilter {
    @Override
    protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
        String url = req.getRequestURL().toString();
        //判断是否为静态资源
        if(!url.endsWith(".js") && !url.endsWith(".css") && !url.endsWith(".png")){
            HttpSession session = req.getSession();
            User user = (User) session.getAttribute("user");
            //判断是否未登陆
            if(user == null && !url.endsWith("login")){
                res.sendRedirect("login");
                return;
            }
        }
        //交给过滤链处理
        chain.doFilter(req, res);
    }
}

现在,我们的页面已经基本完善为我们想要的样子了。

Screenshot 2024-05-09 at 16.51.06