Filter过滤器与Interceptor拦截器

  一、Filter过滤器

1. 定义:

可以统一拦截请求,防止不合法的资源访问,是javaweb三大组件之一(Servlet,Filter,Listener)

2.代码实现

Filter类

定义一个Filter类,实现Filter接口,加上@WebFilter("/*")注解,拦截所有请求

@Slf4j
@WebFilter("/*")
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("Filter初始化");
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("拦截到了请求");
        log.info("拦截放行前");

        HttpServletRequest request = (HttpServletRequest) servletRequest; //向下转型
        Cookie[] cookies = request.getCookies();    //获得cookie
        String token = null;   //获得token
        for(Cookie cookie : cookies){
            if(cookie.getName().equals("token")){
                token = cookie.getValue();
                log.info("token: "+token);
            }
        }

        //验证token
        try{
            Claims claims = JwtUtils.parseJWT(token);   //得到JWT令牌载荷
        } catch (Exception e){//JWT验证失败
            log.info("token失效");
            return;
        }

        log.info("拦截放行后");
        return;
    }

    @Override
    public void destroy() {
        log.info("Filter销毁");
        Filter.super.destroy();
    }
}

在引导类中配置Filter

配置Filter:引导类要加上@ServletComponentScan注解

@ServletComponentScan
@SpringBootApplication
public class TliasApplication {
    public static void main(String[] args) {
        SpringApplication.run(TliasApplication.class, args);
    }
}

3.效果展示

如下图,第一次登录完成后,cookie里成功存储了token的键值对

现在,我们把token改掉,让服务端无法正常解析。

再次访问,就无法访问到了

查看控制台,出现了token失效的提示,说明

try {
    Claims claims = JwtUtils.parseJWT(token);   //得到JWT令牌载荷
} catch (Exception e) {//JWT验证失败
    log.info("token失效");
    return;
}

这一段代码成功执行了, JwtUtils.parseJWT(token)解析出错。

4.过滤器链

当定义好几个过滤器的时候,就形成了过滤器链条,拦截的顺序按照过滤器类命名在字母表中的顺序。

二、Interceptor拦截器

1. 定义

Springboot中用来统一拦截请求,防止不合法的资源访问

2.代码实现

自己编写Interceptor具体实现文件和WebConfig配置文件,项目结构如图

Interceptor代码

要实现HandlerInterceptor接口,常用方法有preHandle()、postHandler()、afterCompletions()方法

方法名执行时机核心作用关键注意事项
preHandle()控制器方法执行前1. 权限校验、登录验证、参数校验;2. 记录请求开始信息;3. 决定是否放行(返回 true/false)返回false则直接拦截,后续postHandleafterCompletion都不会执行
postHandle()控制器方法执行后、视图渲染1. 修改响应数据 / 视图;2. 补充返回参数;3. 记录控制器执行完成信息1. 仅preHandle返回 true 时执行;2. 控制器抛异常则此方法不执行;3. REST 接口(返回 JSON)的modelAndView为 null
afterCompletion()整个请求完全结束后(响应返回客户端)1. 统计请求耗时;2. 资源清理(关闭流、释放连接);3. 记录请求最终状态1. 仅preHandle返回 true 时执行;2. 无论是否抛异常都会执行;3. 可通过ex参数捕获控制器异常

补充执行流程(帮助理解)

客户端发起请求 → 服务器接收请求 → 执行拦截器preHandle → 执行Controller → 执行拦截器postHandle → 服务器渲染视图(传统方案,当前主流的前后端分离模式服务器无需渲染视图,Springboot为了兼容两种模式保留了视图渲染相关的设计) → 执行拦截器afterCompletion → 服务器返回响应 → 客户端收到响应(请求真正结束)

package com.itheima.tlias.interceptor;

import com.itheima.tlias.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
@Component
public class DemoInteceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("拦截到了请求");
        log.info("拦截放行前");

        if(request.getRequestURI().contains("login")){  //登录请求直接放行
            return true;
        }

        Cookie[] cookies = request.getCookies();    //获得cookie
        if(cookies != null) {
            String token = null;   //获得token
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("token")) {
                    token = cookie.getValue();
                    log.info("token: " + token);
                }
            }

            //验证token
            try {
                Claims claims = JwtUtils.parseJWT(token);   //得到JWT令牌载荷
            } catch (Exception e) {//JWT验证失败
                log.info("token失效");
                return false;
            }
        }

        log.info("拦截放行后");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion");
    }
}

WebConfig代码

注意要添加@Configuration注解,标明是配置类

通过重载addInterceptor添加拦截器,addPathPatterns设置可拦截的路径,excludePathPatterns排除拦截路径。

常见路径有/*,/**,/depts/*,/emps/**

拦截路径规则详解表

拦截路径核心匹配规则匹配的请求示例(✅)不匹配的请求示例(❌)典型使用场景
/*匹配根目录下的一级路径(不含/,不匹配根路径//login/register/depts/emps/depts/list/emps/1/edit/user/info仅拦截根目录下的一级接口,不拦截多级路径
/**匹配所有路径(包括根路径、一级、多级路径)//login/depts/depts/list/emps/1/edit/user/info/2无,所有路径可匹配拦截所有请求,再放行特定接口(如登录、静态资源)
/depts/*匹配/depts目录下的一级路径(不匹配/depts本身)/depts/list/depts/add/depts/delete/depts/depts/1/detail/emps/list/login仅拦截/depts模块下的一级接口,不拦截二级及以上
/emps/**匹配/emps目录下的所有层级路径(包括/emps本身)/emps/emps/list/emps/1/edit/emps/2/delete/batch/depts/list/login/user/info拦截/emps模块下的所有接口(按模块拦截核心用法)
package com.itheima.tlias.config;

import com.itheima.tlias.interceptor.DemoInteceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new DemoInteceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login","depts/*","emps/**");
    }
}

3.效果展示

是否排除/emps/**被拦截为例子,进行展示。

不拦截/emps/**

/emps/**加入excludePathPattern,表示不拦截/emps模块下的所有接口,代码如下。

.addPathPatterns("/**")
.excludePathPatterns("/login","depts/*","/emps/**");

此时,可以看到,即使token改为不合法的“aaa”,localhost:8080/emps也能成功查询到所有员工数据。说明/emps并没有被拦截,excludePathPattern生效了。

拦截/emps/**

现在,将/emps/**从excludePathPattern中移除,表示拦截员工/emps模块下所有接口,代码如下。

.addPathPatterns("/**")
.excludePathPatterns("/login","depts/*");

结果如下,token改为不合法的“aaa”,/emps请求被拦截下来了

现在,我们通过登录去得到一个有效的token,把token改为有效值再查询一次。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值