365bet亚洲真人网址-365双试投注-365体育平台bet下载入口

过滤器与拦截器 - 登录校验与登录认证(JWT令牌技术)

文章目录 登录校验与登录认证一、登录认证1.1 基础登录功能1.2 会话技术1.2.1 介绍1.2.2 方案一 Cookie1.2.2.1 基本介绍1.2.2.2 服务端向浏览器响应Cooki

过滤器与拦截器 - 登录校验与登录认证(JWT令牌技术)

文章目录

登录校验与登录认证一、登录认证1.1 基础登录功能1.2 会话技术1.2.1 介绍1.2.2 方案一 Cookie1.2.2.1 基本介绍1.2.2.2 服务端向浏览器响应Cookie1.2.2.3 浏览器向服务端请求携带Cookie

1.2.3 方案二 Session1.2.3.1 基本介绍1.2.3.2 服务端向浏览器响应Session1.2.3.3 浏览器向服务端请求携带Session

二、JWT 令牌技术 - 主流2.1 基本介绍2.2 JWT令牌 生成2.2.1 Maven2.2.2 生成JWT令牌

2.3 JWT令牌 校验2.4 登录成功下发令牌2.4.1 封装工具类2.4.2 发放JWT令牌

三、 Filter3.1 基本介绍3.2 Filter 快速入门3.3 执行流程3.4 拦截路径3.5 过滤器链3.6 登录校验过滤器3.6.1 实现思路3.6.2 代码实现

四、Interceptor - 拦截器4.1 入门4.2 详解4.2.1 拦截路径4.2.2 执行流程4.2.3 过滤器与拦截器的区别

4.3 登录校验拦截器4.3.1 实现思路4.3.2 代码实现

登录校验与登录认证

一、登录认证

1.1 基础登录功能

接口

@Slf4j

@RestController

public class LoginController {

@Autowired

private EmpService empService;

// 用Emp对象接收用户名和密码,里面将属性封装好了

@PostMapping("/login")

public Result login(@RequestBody Emp emp) {

log.info("员工登录{}",emp);

Emp e = empService.login(emp);

return e!=null? Result.success() :Result.error("用户名或密码错误");

}

}

SQL

@Select("select * from emp where username =#{username} and password = #{password}")

Emp getByUsernameAndPassword(Emp emp);

1.2 会话技术

1.2.1 介绍

会话:用户打开浏览器,访问web服务器资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。

比如我们打开浏览器与Web服务器建立连接。首先访问login接口,再访问depts接口,最后访问emps接口。只要浏览器和服务器都没有关闭,那么这三次请求都是在一次会话中完成的。

关闭服务器,所有的会话都会关闭

关闭当前浏览器,当前会话结束

会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据。

http请求是无状态的,下一次请求并不会携带上一次请求的数据,每一次请求都是相互独立额,也就保证了http协议它的效率是比较高的。由于是无状态的,我们也无法确定两次请求是否来自于同一个浏览器,是否来自于同一个会话。此时同一个会话的多个请求之间是没有办法共享数据的。

我们要想解决这个问题,就需要会话跟踪技术。

会话跟踪方案:

客户端会话跟踪技术:Cookie 存储在客户端浏览器中服务端会话跟踪技术:Session 存储在服务器当中令牌技术

Cookie 与Session 是传统web开发当中所提供的的两种会话跟踪技术,而当前企业开发中最主流的是令牌技术

1.2.2 方案一 Cookie

1.2.2.1 基本介绍

存储在客户端浏览器,使用Cookie跟踪对话,就可以在浏览器第一次发起请求来请求浏览器的时候设置一个Cookie。

我们在Cookie中可以存储一些信息,比如存储用户名,用户id。服务端在给客户端响应数据的时候会自动将Cookie响应给浏览器。

浏览器接收到服务端响应的Cookie后将其存储在浏览器本地。

之后客户端每次发请求都会将本地存储的Cookie携带到服务端。我们在服务端就可以获取用户的信息,也可以判断Cookie是否存在。

如果不存在说明这个客户端之前没有访问登录接口;如果存在说明这个客户端之前已经登录完成了。

这样我们就能在同一次会话的不同请求之前来共享数据

三个自动

服务器自动将Cookie响应给浏览器浏览器接收到响应回来的数据之后会自动的将Cookie存储在浏览器本地后续请求中浏览器会自动将Cookie携带到服务端

为什么上面这个三个时自动进行的呢?

因为Cookie是http协议支持的内容,各大浏览器厂商都支持了这一标准。

在HTTP协议中,提供了响应头(setCookie)和一个请求头

HTTP相关技术文档

https://cloud.tencent.com/developer/doc/1117

服务端在给浏览器响应Cookie的时候是以哪种方式响应回去的?

直接设置了一个响应头Set-Cookie,请求头所对应的数据就是Cookie对应的值。

“name”就是Cookie的名称,“value”就是Cookie的值

此响应头返回给浏览器,浏览器会自动解析响应头

优点

HTTP 协议中支持的技术

缺点

移动端APP无法使用Cookie

不安全,用户可以自己禁用Cookie

Cookie不能跨域(协议、IP/域名、端口号,这三者有一个不同就是跨域)

1.2.2.2 服务端向浏览器响应Cookie

//设置Cookie - 服务器要给浏览器响应数据

@GetMapping("/c1")

public Result cookie1(HttpServletResponse response){

response.addCookie(new Cookie("login_username","itheima")); //设置Cookie/响应Cookie

return Result.success();

}

效果图

自动保存在下图位置

1.2.2.3 浏览器向服务端请求携带Cookie

服务端解析从浏览器向服务端请求携带的Cookie

//获取Cookie

@GetMapping("/c2")

public Result cookie2(HttpServletRequest request){

Cookie[] cookies = request.getCookies();

for (Cookie cookie : cookies) {

if(cookie.getName().equals("login_username")){

System.out.println("login_username: "+cookie.getValue()); //输出name为login_username的cookie

}

}

return Result.success();

}

1.2.3 方案二 Session

1.2.3.1 基本介绍

服务器端会话跟踪技术,存储在服务器端,底层借助Cookie实现。

浏览器在第一次请求服务器时,我们可以直接在服务器当中获取到会话对象Session(第一次请求会话对象Session是不存在的,服务器会自动创建一个会话对象),每一个会话对象都有一个id。

之后服务端再给浏览器响应数据的时候,会将Session的id通过Cookie响应给浏览器,其实就是在响应头重增加了一个Set-Cookie。

在这里Cookie的名字是固定的,就是JSESSIONID,代表的就是服务端会话对象Session的id。

浏览器接收到数据之后会自动将这个Cookie存储在浏览器本地,之后再请求服务端时都会将Cookie数据获取出来并且携带到服务端。

浏览器拿到JSESSIONID也就是Session的id后,会从众多会话对象Session中找到当前请求对应的绘画对象Session。

找到对应Session之后,就可以实现在同一次会话的多次请求之间来共享数据

优点

存储在服务端,安全

缺点

服务器集群环境下无法直接使用SessionCookie的缺点(底层Cookie实现)

1.2.3.2 服务端向浏览器响应Session

// 往HTTPSession中存储值

// 服务器会判断当前这次请求对应的会话对象Session是否存在,

// 如果不存在会新创建一个Session,如果存在会获取当前这一次请求对应的Session

@GetMapping("/s1")

public Result session1(HttpSession session){

log.info("HttpSession-s1: {}", session.hashCode());//HttpSession-s1: 1750219908

session.setAttribute("loginUser", "tom"); //往session中存储数据

return Result.success();

}

Set-Cookie

Application

1.2.3.3 浏览器向服务端请求携带Session

// 这个地方我们可以声明HttpSession对象,也可以使用HttpServletRequest对象

@GetMapping("/s2")

public Result session2(HttpServletRequest request){

HttpSession session = request.getSession();//拿到当前这次请求对应的会话对象

log.info("HttpSession-s2: {}", session.hashCode()); //HttpSession-s2: 1750219908

Object loginUser = session.getAttribute("loginUser"); //从session中获取数据

log.info("loginUser: {}", loginUser); //loginUser: tom

return Result.success(loginUser);

}

注意看上面的几张图,页面中完全没有涉及到“loginUser”的存储,那为什么控制台还能输出“loginUser: tom”?

​ Session存储在服务器端,每次请求浏览器都会写到Cookie,并且有JSESSIONID,服务端获取到之后就可以解析,确定是哪个Session对象

而且观察控制台SessionID,确实是同一个

二、JWT 令牌技术 - 主流

用户身份表示

存储在客户端。不用担心安全问题,浏览器携带令牌请求时,服务端会进行校验。

无效的,返回错误结果;有效的,访问对应权限。

优点

支持PC端、移动端解决集群环境下的认证问题减轻服务器端存储压力

缺点

需要自己实现

2.1 基本介绍

官方网站:JSON Web Tokens - jwt.io

简洁、自包含的格式,用于在通信双方以JSON数据格式安全的传输信息。由于数字签名的存在,这些信息都是可靠的。

组成:

第一部分:Header(头),记录令牌类型、签名算法等。

例如:[“alg”:“HS256”,“type”:"WT”)

第二部分:Payload(有效载荷),携带一些自定义信息、默认信息等。

例如:“id”."1"“username”."Tom”

第三部分: Signature(签名),防止Token被篡改、确保安全性。

​ 将header、payload,并加入指定秘钥,通过指定签名算法计算而来。

​ 第三部分字符的由来不是Base64编码方式生成的,而是前面指定的签名算法

JSON数据格式是怎么变成一些字符的呢?

通过Base64编码方式

应用场景

​ 登录认证。

① 用户登录成功后,服务端生成一个JWT令牌,并传输给前端。

②前端拿到JWT令牌之后会将其存储起来,之后前端的每一次请求都会将JWT令牌携带到服务端,服务端会对请求进行统一拦截,拦截之后先判断有没有把这个令牌带过来。

​ 如果没有令牌就拒绝访问;若有令牌但是无效仍然拒绝访问;若有效则直接放心,并处理对应请求

2.2 JWT令牌 生成

2.2.1 Maven

无论生成和校验都需要下面的工具类

io.jsonwebtoken

jjwt

0.9.0

2.2.2 生成JWT令牌

签名算法具体有哪些,可以查看官网

/**

* 生成JWT

*/

@Test

public void testGenJwt() {

Map map = new HashMap<>();

map.put("id", 1);

map.put("name", "tom");

// 链式编程 - Jwt令牌在生成的时候所需要设置的一些参数

String jwt = Jwts.builder()

// 存储在第一个部分 参数一 数字签名算法 参数二 秘钥

.signWith(SignatureAlgorithm.HS256, "zhangjingqi")

// JWT令牌所存储的内容(自定义数据,存储在第二个部分,原始自定义数据是JSON格式)

// 可以是Map集合,也可以是Claims对象

.setClaims(map)

// 设置令牌有效期 - 一个小时后过期, 因为是毫秒,3600*1000代表一个小时

.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))

// 调用compact会有一个String返回值,就是JWT令牌

.compact();

System.out.println(jwt);//eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTY4NDIxNjUzNX0.s33vECyehznKMrbDqD1Pdx-DrHWkscdyNeWmLnY-ArU

}

将生成的JWT放在官网进行解码,和我们的数据一模一样

2.3 JWT令牌 校验

Jwt令牌生成后,不论我们改哪部分的字符,在解析的时候都会报错,所以Jwt令牌是很安全的。

令牌时间过期之后也不能访问

@Test

public void testParseJwt(){

Claims claims = Jwts.parser()

// 指定签名秘钥

.setSigningKey("zhangjingqi")

// 解析JTW令牌

.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTY4NDIxNjUzNX0.s33vECyehznKMrbDqD1Pdx-DrHWkscdyNeWmLnY-ArU")

// 拿到了我们自定义的内容,也就是Jwt令牌的第二个部分

.getBody();

System.out.println(claims); //{name=tom, id=1, exp=1684216535}

}

注意事项

JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的(编码和解析时秘钥必须相同)

如果JWT令牌解析校验时报错,则说明JWT令牌被篡改或失效,令牌非法

2.4 登录成功下发令牌

令牌生成: 登录成功后,生成JWT令牌,返回给前端令牌校验,在请求到达服务端后,对令牌进行统一拦截、校验

用户登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,都需要在请求头header中携带到服务端,请求头的名称为token,值为登录时下发的JWT令牌

2.4.1 封装工具类

将上面编码和解码汇编成一个工具类供我们使用

public class JwtUtils {

private static String signKey = "zhangjingqi";

private static Long expire = 43200000L;

/**

* 生成JWT令牌

* @param claims JWT第二部分负载 payload 中存储的内容

* @return

*/

public static String generateJwt(Map claims){

String jwt = Jwts.builder()

.addClaims(claims)

.signWith(SignatureAlgorithm.HS256, signKey)

.setExpiration(new Date(System.currentTimeMillis() + expire))

.compact();

return jwt;

}

/**

* 解析JWT令牌

* @param jwt JWT令牌

* @return JWT第二部分负载 payload 中存储的内容

*/

public static Claims parseJWT(String jwt){

Claims claims = Jwts.parser()

.setSigningKey(signKey)

.parseClaimsJws(jwt)

.getBody();

return claims;

}

}

2.4.2 发放JWT令牌

// 用Emp对象接收用户名和密码,里面将属性封装好了

@PostMapping("/login")

public Result login(@RequestBody Emp emp) {

log.info("员工登录{}",emp);

Emp e = empService.login(emp);

// 登陆成功,生成令牌并下发令牌

if(e!=null){

Map claims = new HashMap<>();

claims.put("id",e.getId());

claims.put("name",e.getName());

claims.put("username",e.getUsername());

// 生成令牌,员工信息已经在里面了

String jwt = JwtUtils.generateJwt(claims);

return Result.success(jwt);

}

// 登录失败,返回错误信息

return Result.error("用户名或密码错误");

}

网页联调

接收编码后,前端人员将其存储到Local Storage中

这里面的Key “tlias_token”是前端自己定义的

随便抓取一个请求,看此时是否携带Jwt令牌

显然是存在的。这个地方的实现是前端完成的,后端不需要管

三、 Filter

Filter过滤器,是javaWeb三大组件(Servlet、Filter、Listener)之一

3.1 基本介绍

概念:

过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能

​ ① 想要访问服务器中的某些资源,必须先经过Filter过滤器。

​ ② 再此处进行一些操作,完成之后进行放行,访问对应的资源

​ ③ 资源访问完毕,最后再回到过滤器,然后再给浏览器响应对应的数据

过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。

​ 如果没有过滤器,我们需要在每一个接口中编写登录校验逻辑。

​ 如果登录了,放行去访问对应的信息,如果没有登录,直接在Filter中返回错误信息,不再访问后面的请求

3.2 Filter 快速入门

定义Filter:定义一个类,实现Filter接口,并重写其所有方法

但是开发中我们一般只实现doFilter这个方法,其他两个方式使用默认实现即可

// 定义Filter,并重写三个方法

// 在web服务器启动的时候,会自动创建Filter过滤器对象

//不配置的话过滤器不会生效,urlPatterns表示拦截什么样的请求,/*代表拦截所有请求

@WebFilter(urlPatterns = "/*")

public class DemoFilter implements Filter {

// 初始化方法,过滤器创建完毕之后会自动调用init方法,只会调用一次(只会在创建时调用一次)

// 一般在这里完成一些资源及环境的准备操作

public void init(FilterConfig filterConfig) throws ServletException {

// Filter.super.init(filterConfig);

System.out.println("init 初始化方法执行了");

}

// 每一次拦截到请求都会调用的方法,最为重要的方法,是会被调用多次

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {

System.out.println("拦截方法执行,拦截到了请求 ...");

// 往下放行去访问对应的资源,如果不放行,页面获取不到对应数据(接口资源是获取不到的)

chain.doFilter(request, response);

}

// 销毁方法。服务区关闭时调用,只调用一次

// 一般在这里完成资源的释放和环境的清理操作

public void destroy() {

// Filter.super.destroy();

System.out.println("destroy 销毁方法执行了 ");

}

}

配置Filter:Filter类上添加@WebFilter注解,配置拦截资源路径。引导类上添加@ServletComponentScan注解开启Servlet组件支持

//Filter是javaweb三大组件之一,不是Spring提供的,如果想要使用三大组件,需要添加这个注解

@ServletComponentScan

@SpringBootApplication

public class SpringbootWebApplication {

public static void main(String[] args) {

SpringApplication.run(SpringbootWebApplication.class, args);

}

}

启动程序,观察控制台

init方法只会执行这一次

随意访问几个接口,观察控制台

3.3 执行流程

当我们的过滤器拦截到请求之后我们需要完成一个非常重要的操作,那就是放行。

chain.doFilter(request, response);

在过滤器放行之前我们可以执行一段逻辑。

”放行“就是让其去访问对应的web资源,访问完过滤器之后还会回到过滤器当中,执行“放行”语句后面的代码,执行完毕之后再给浏览器响应数据

chain.doFilter(request, response);

System.out.println("执行放行后逻辑 ...");

放行后访问对应资源,资源访问完成后还会回到Filter中吗?

​ 会

如果回到Filter中,是重新执行还是执行放行后的逻辑?

​ 执行放行后的逻辑

3.4 拦截路径

在快速入门中配置的是 /*,代表拦截所有请求

@WebFilter(urlPatterns = "/*")

public class DemoFilter implements Filter {}

拦截路径urlPatterns含义拦截具体路径/login只访问/login路径时才会被拦截目录拦截/emps/*访问/emps下的所有资源,都会被拦截拦截所有/*访问所有资源,都会被拦截

3.5 过滤器链

一个web应用中,可以配置多个过滤器,多个过滤器形成了一个过滤器链。

​ 过滤器链中的过滤器会一个一个的执行,第一个放行之后会执行第二个,依次推,最后一个过滤器执行完后会访问对应请求。

​ 过滤器链中最后一个过滤器放行的话,会放行到web资源当中来访问web资源

​ 访问完资源后,是倒着进行的,先执行最后一个过滤器,再倒数第二个…

注解配置Filter,优先级是按照过滤器类型(字符串)的自然排序

创建新的过滤器

@WebFilter(urlPatterns = "/*")

public class AbcFilter implements Filter {

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

System.out.println("Abc拦截方法执行,拦截到了请求 ...");

filterChain.doFilter(servletRequest, servletResponse);

System.out.println("Abc执行放行后逻辑 ...");

}

}

控制台输出:(我们之前创建了一个DemoFilter过滤器)

Abc拦截方法执行,拦截到了请求 … Demo拦截方法执行,拦截到了请求 …

Demo执行放行后逻辑 … Abc执行放行后逻辑 …

3.6 登录校验过滤器

备注说明:

用户登录成功后,系统会自动下发JWT令牌,然后在后续的每次请求中,都需要在请求头header中携带到服务端,请求头的名称为token,值为登录时下发的JWT令牌。

如果检测到用户未登录,则会返回如下固定错误信息。

所有的请求,拦截到之后,都需要校验令牌吗?

​ 登录请求例外

拦截到请求后,什么情况下可以放行,执行业务操作?

​ JWT令牌存在且令牌校验通过(合法),否则都会返回未登录错误结果

3.6.1 实现思路

获取请求url判断请求url中是否包含login,如果包含,说明是登录操作,放行获取请求头中的令牌(token)判断令牌是否存在,如果不存在,返回错误结果(未登录)解析token,如果解析失败,返回错误结果(未登录)放行

3.6.2 代码实现

在过滤器当中为什么要把ServletRequest类型强转成HttpServletRequest类型?

在Java中,ServletRequest是一个接口,它是由Servlet容器提供的。HttpServletRequest接口则是ServletRequest接口的子接口,它包含了一些用于HTTP协议的方法和属性。在Java Web应用程序中,Servlet容器实现了ServletRequest和HttpServletRequest接口,并使用HttpServletRequest实现了HTTP协议相关的逻辑。

在开发Web应用程序时,Servlet容器将在每个客户端请求到达时创建一个ServletRequest对象并将其传递给请求处理器。由于具体的实现是由Servlet容器提供的并且通常是HttpServletRequest,因此在编写Servlet处理器时,我们通常将ServletRequest对象强制转换成HttpServletRequest对象,以便能够调用提供的HTTP协议相关方法。

因此,在过滤器中,如果我们需要使用HttpServletRequest接口中特定的HTTP协议相关方法,我们需要将ServletRequest对象强制转换成HttpServletRequest对象。这样我们才能够在处理ServletRequest对象时,使用HttpServletRequest中更多的方法和属性。

注意!!!将刚刚测试的Filter注释掉,只留这一个过滤器!!!!!!!!

@Slf4j

@WebFilter(urlPatterns = "/*")

public class LoginCheckFilter implements Filter {

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

// ServletRequest、ServletResponse是父类,

// 请求对象与响应对象

HttpServletRequest request = (HttpServletRequest) servletRequest;

HttpServletResponse response = (HttpServletResponse) servletResponse;

// TODO 1.获取请求url

String requestURL = request.getRequestURL().toString(); //不toString就是StringBuffer类型

log.info("请求的url:{}", requestURL);

// TODO 2.判断请求url中是否包含login,如果包含,说明是登录操作,放行

if (requestURL.contains("/login")){

log.info("登录操作,放行...");

filterChain.doFilter(request, response);

// 登录操作不需要执行下面的逻辑,直接结束此过滤器即可

return;

}

// TODO 3.获取请求头中的令牌(token)

String token = request.getHeader("token");

// TODO 4.判断令牌是否存在,如果不存在,返回错误结果(未登录)

if (!StringUtils.hasLength(token)) { //spring当中的工具类

// 说明字符串为null,返回错误结果(未登录)

log.info("请求头token为空,返回未登录的信息");

Result error = Result.error("NOT_LOGIN");

// 手动转JSON

String errorJson = JSON.toJSONString(error);

// response.getWriter()获取输出流,write()直接将数据响应给浏览器

response.getWriter().write(errorJson);

return;

}

// TODO 5.解析token,如果解析失败,返回错误结果(未登录)

// 说明存在令牌,校验

try{

Claims claims = JwtUtils.parseJWT(token);

}catch (Exception e){ // 出现异常代表着解析失败

e.printStackTrace();

log.info("解析令牌失败,返回未登录错误信息");

Result error = Result.error("NOT_LOGIN");

// 手动转JSON

String errorJson = JSON.toJSONString(error);

// response.getWriter()获取输出流,write()直接将数据响应给浏览器

response.getWriter().write(errorJson);

return;

}

// 到这里说明令牌解析成功,直接放行

// TODO 6.放行

log.info("令牌合法,放行");

filterChain.doFilter(request, response);

}

}

很完美

四、Interceptor - 拦截器

之前做的笔记: Springboot——拦截器_springboot 拦截器_

概念:是一种动态拦截方法调用调用机制,类似过滤器。Spring框架中提供的,用来动态拦截控制器方法的执行(拦截请求的)

作用: 拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码

4.1 入门

在测试之前可以把过滤器关掉,否则一直验证token比较麻烦

定义拦截器,实现HandlerInterceptor接口,并且重写其所有方法

@Component

public class LoginCheckInterceptor implements HandlerInterceptor {

// 目标资源方法执行前执行(Controller方法执行之前), true:放行, false:不放行

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

System.out.println("preHandle......");

// return HandlerInterceptor.super.preHandle(request, response, handler);

return true;

}

// 目标资源方法执行后执行

@Override

public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

System.out.println("postHandle.....");

// HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);

}

// 视图渲染完毕后执行,最后执行

@Override

public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

// HandlerInterceptor.super.afterCompletion(request, response, handler, ex);

System.out.println("afterCompletion......");

}

}

注册拦截器

@Configuration

public class WebConfig implements WebMvcConfigurer {

@Autowired

private LoginCheckInterceptor loginCheckInterceptor;

@Override

public void addInterceptors(InterceptorRegistry registry) {

registry.addInterceptor(loginCheckInterceptor)

.addPathPatterns("/**");

}

}

4.2 详解

4.2.1 拦截路径

addPathPatterns 指定拦截哪些路径

excludePathPatterns 执行不拦截哪些不经

registry.addInterceptor(loginCheckInterceptor)

.addPathPatterns("/**")

.excludePathPatterns("/login");

拦截路径含义举例/*一级路径能匹配/depts,/emps,/login,不能匹配/depts/1/**任意级路径能匹配/depts/1,/depts,/depts/1/2/depts/*/depts下一级路径能匹配/depts/1,不能匹配/depts,/depts/1/2,/depts/depts/**/depts下的任意路径能匹配/depts,/depts/1,/depts,/depts/1/2

4.2.2 执行流程

① 当浏览器向Web服务器发送请求时,我们所设定的过滤器会拦截到这一请求。

② 过滤器先执行放行前逻辑,在此处决定是否放行

③ 放行之后进入到Spring环境中,进入DispatcherServlet

​ 在请求响应时说道,tomcat服务器并不识别我们所编写的controller程序,但是他是识别Servlet程序的,因为tomcat是一个Servlet程序。

​ 而在SpringWeb当中提供了一个非常核心的Servlet,我们叫做DispatcherServlet前端核心控制器,所以请求会先进入到DispatcherServlet,请求由DispatcherServlet再传给Controller

​ 如果设置了拦截器的话,DispatcherServlet在传给Controller之前需要先被拦截器拦截住

④ 拦截器拦截到,先进行preHandle,决定是否放行,如果放行便访问Controller层方法

⑤Controller层方法完成之后,再执行postHandler方法已经afterCompletion方法

⑥返回给DispatcherServlet

⑦最终执行放行后逻辑

⑧最终给浏览器响应数据

4.2.3 过滤器与拦截器的区别

接口规范不同:过滤器实现Filter接口,而拦截器需要实现HandlerInterceptor接口

拦截范围不同:过滤器Filter会拦截所有资源,而Interceptor只会拦截Spring环境中的资源,过滤器拦截范围更大

4.3 登录校验拦截器

4.3.1 实现思路

与过滤器思路一模一样

获取请求url判断请求url中是否包含login,如果包含,说明是登录操作,放行获取请求头中的令牌(token)判断令牌是否存在,如果不存在,返回错误结果(未登录)解析token,如果解析失败,返回错误结果(未登录)放行

4.3.2 代码实现

测试之前记得吧过滤器注解注释掉

// 目标资源方法执行前执行(Controller方法执行之前), true:放行, false:不放行

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

// TODO 1.获取请求url

String requestURL = request.getRequestURL().toString(); //不toString就是StringBuffer类型

log.info("请求的url:{}", requestURL);

// TODO 2.判断请求url中是否包含login,如果包含,说明是登录操作,放行

if (requestURL.contains("/login")) {

log.info("登录操作,放行...");

return true;

}

// TODO 3.获取请求头中的令牌(token)

String token = request.getHeader("token");

// TODO 4.判断令牌是否存在,如果不存在,返回错误结果(未登录)

if (!StringUtils.hasLength(token)) { //spring当中的工具类

// 说明字符串为null,返回错误结果(未登录)

log.info("请求头token为空,返回未登录的信息");

Result error = Result.error("NOT_LOGIN");

// 手动转JSON

String errorJson = JSON.toJSONString(error);

// response.getWriter()获取输出流,write()直接将数据响应给浏览器

response.getWriter().write(errorJson);

return false;

}

// TODO 5.解析token,如果解析失败,返回错误结果(未登录)

// 说明存在令牌,校验

try {

Claims claims = JwtUtils.parseJWT(token);

} catch (Exception e) { // 出现异常代表着解析失败

e.printStackTrace();

log.info("解析令牌失败,返回未登录错误信息");

Result error = Result.error("NOT_LOGIN");

// 手动转JSON

String errorJson = JSON.toJSONString(error);

// response.getWriter()获取输出流,write()直接将数据响应给浏览器

response.getWriter().write(errorJson);

return false;

}

// 到这里说明令牌解析成功,直接放行

// TODO 6.放行

log.info("令牌合法,放行");

// return HandlerInterceptor.super.preHandle(request, response, handler);

return true;

}

← 上一篇: 2025年各行信用卡提额周期表及成功提额的关键
下一篇: 逸剑风云决矿石在哪里获得-全矿石获取位置介绍 →

相关推荐

情侣之间的小情趣如何保持新鲜感?

情侣之间的小情趣如何保持新鲜感?

情侣之间的升温小技巧,私下一起悄悄玩。如何保持新鲜感?这是一个许多情侣都关心的问题。在这里,囤囤菌就给大家讲讲一些情侣之间的小

拌合站生产质量远程监控系统

拌合站生产质量远程监控系统

拌合站生产质量远程监控系统 运用质量动态管理的方法,采用软硬件结合的手段,对拌合站生产数据进行有效监控。实时采集拌合站生产的每盘

绝地求生雨林怎么玩,雨林地图选路吃鸡攻略

绝地求生雨林怎么玩,雨林地图选路吃鸡攻略

绝地求生雨林图是伏地魔的天下,玩家选择路线时需要小心不要踩到,那么究竟绝地求生雨林怎么玩?接下来小编带来了雨林地图选路吃鸡攻略

阿娇的实际身高是多少?

阿娇的实际身高是多少?

阿娇身高是160cm。 钟欣潼昵称阿娇,出生于中国香港,毕业于皇家墨尔本理工大学,中国香港女歌手、演员,华语女子演唱组合“Twins”成员。 1

防诈小课堂

防诈小课堂

一、别慌!先做这三件事,把损失降到最低 报警不是走流程,是抢时间的救命动作 很多人觉得报警没用,觉得钱转出去就回不来了。但真实案

採的解释

採的解释

(采)捋取也。大雅曰。捋采其劉。周南芣苢傳曰。采、取也。又曰。捋、取也。是采捋同訓也。詩又多言采采。卷耳傳曰。采采、事采之也。此