一、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则直接拦截,后续postHandle和afterCompletion都不会执行postHandle()控制器方法执行后、视图渲染前 1. 修改响应数据 / 视图;2. 补充返回参数;3. 记录控制器执行完成信息 1. 仅 preHandle返回 true 时执行;2. 控制器抛异常则此方法不执行;3. REST 接口(返回 JSON)的modelAndView为 nullafterCompletion()整个请求完全结束后(响应返回客户端) 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改为有效值再查询一次。



1223

被折叠的 条评论
为什么被折叠?



