SpringBoot3中token攔截器鏈的設(shè)計與實現(xiàn)步驟
流程分析
用戶在進行登陸后服務(wù)器會發(fā)放token等信息一起返回給前端,前端會進行保存,那么token里面是攜帶一些有關(guān)用戶的身份等信息的,用戶端在請求后端時需要在請求頭攜帶token,請求先被攔截器截獲,只有經(jīng)過多重攔截器校驗通過后才可以執(zhí)行對應(yīng)功能接口,否則會拋出異常返回對應(yīng)錯誤信息。
需要清楚的
- 每次登錄都要刷新token信息,
- 不能在用戶訪問的過程中token過期,只要用戶訪問,token就要刷新有效期。
- 如果token正確解析token中的用戶id,根據(jù)用戶id查詢用戶信息。
實現(xiàn)步驟
總的來說大致分為4步:
1定義攔截器--->2創(chuàng)建攔截器鏈配置類--->3配置攔截器鏈順序--->4配置攔截排除項
1.定義攔截器
首先,需要定義第一個攔截器類,該攔截器類需要實現(xiàn) Spring 框架提供的 HandlerInterceptor 接口。該攔截器只做一件事就是刷新token。
import cn.hutool.json.JSONUtil;
import com.mijiu.commom.util.JwtUtils;
import com.mijiu.commom.util.UserHolder;
import com.mijiu.entity.User;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
* @author mijiupro
*/
@Slf4j
@Component
public class RefreshTokenInterceptor implements HandlerInterceptor {
private final JwtUtils jwtUtils;
private final StringRedisTemplate stringRedisTemplate;
public RefreshTokenInterceptor(JwtUtils jwtUtils, StringRedisTemplate stringRedisTemplate) {
this.jwtUtils = jwtUtils;
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1、從請求頭中獲取token
String authorizationHeader = request.getHeader("authorization");
if (StringUtils.isBlank(authorizationHeader)) {
return true;
}
// 2.解析token
Claims claims = jwtUtils.parseToken(authorizationHeader);
if (Objects.isNull(claims)) {
return true;
}
// 3.獲取用戶信息
Integer userId = claims.get("userId", Integer.class);
String userInfoJson = stringRedisTemplate.opsForValue().get("login:user:" + userId);
if (StringUtils.isBlank(userInfoJson)) {
return true;
}
// 4.刷新token
String refreshToken = jwtUtils.refreshToken(authorizationHeader);
response.setHeader("Access-Control-Expose-Headers", "Authorization");
response.addHeader("Authorization", refreshToken);
stringRedisTemplate.expire("login:user:" + userId, 30, TimeUnit.MINUTES);
// 5.將用戶信息存入本地線程方便獲取
User user = JSONUtil.toBean(userInfoJson, User.class);
UserHolder.setInfoByToken(user);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
// 清理本地線程
UserHolder.clear();
}
}值得注意:因為有些接口是不需要認證的比如你在商城,瀏覽商品,是不是不登錄也可以瀏覽。不登錄就沒token,沒token就直接放行(認證交給后續(xù)的認證攔截器),有token就直接刷新(不可能你登錄了瀏覽了30分鐘,突然下單然后告訴你token過期重新登錄吧,所以登錄后調(diào)用的每個接口都要走一遍token刷新)。最后請求處理完一定要清理一下本地線程,不然用戶多的時候內(nèi)存占用會很大。
然后,就要實現(xiàn)一個認證攔截器了,實現(xiàn)用戶身份認證。
import com.mijiu.commom.util.UserHolder;
import com.mijiu.entity.User;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Objects;
/**
* @author mijiupro
*/
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User user = UserHolder.getInfoByToken();
if (Objects.isNull(user)) {
response.setStatus(401);
return false;
}
return true;
}
}值得注意:在上個攔截器我們是做過解析token了并存在本地線程里面,所以只需要判斷本地線程有沒有即可。
2.創(chuàng)建攔截器鏈配置類
創(chuàng)建一個配置類,用于配置攔截器鏈。在該配置類中,通過實現(xiàn) WebMvcConfigurer 接口來添加攔截器,具體包括 addInterceptors 方法。
import com.mijiu.commom.interceptor.LoginInterceptor;
import com.mijiu.commom.interceptor.RefreshTokenInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author mijiupro
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final RefreshTokenInterceptor refreshTokenInterceptor;
private final LoginInterceptor loginInterceptor;
public WebConfig(RefreshTokenInterceptor refreshTokenInterceptor, LoginInterceptor loginInterceptor) {
this.refreshTokenInterceptor = refreshTokenInterceptor;
this.loginInterceptor = loginInterceptor;
}
@Override
public void addInterceptors( InterceptorRegistry registry) {
registry.addInterceptor(refreshTokenInterceptor)
.addPathPatterns("/**").order(0);//設(shè)置攔截器對所有路徑生效,執(zhí)行順序為0
registry.addInterceptor(loginInterceptor)
.excludePathPatterns("/captcha/graph-captcha")//排除用戶登錄獲取驗證碼接口
.excludePathPatterns("/","*/login","*.html","/images/**","/doc.html"
,"/webjars/**","/swagger-resources","/swagger-resources/**","/v3/**")//排除登錄獲取靜態(tài)資源、swagger接口文檔等。
.order(1);//設(shè)置攔截器對所有路徑生效,執(zhí)行順序為1
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 對所有路徑生效
.allowedOrigins("*") //允許所有源地址
.allowedMethods("GET", "POST", "PUT", "DELETE") // 允許的請求方法
.allowedHeaders("*"); // 允許的請求頭
}
}3.配置攔截器鏈順序
刷新token的攔截器要最先執(zhí)行,接著才是認證攔截器


4.配置攔截排除項
像用戶登錄的驗證碼接口、登錄接口以及像一些靜態(tài)資源、網(wǎng)頁、圖片等需要進行攔截排除,如果整合了swagger接口文檔也是需要排除的。

最后
token攔截器鏈的設(shè)計與實現(xiàn)核心就四步:
1定義攔截器--->2創(chuàng)建攔截器鏈配置類--->3配置攔截器鏈順序--->4配置攔截排除項
到此這篇關(guān)于SpringBoot3中token攔截器鏈的設(shè)計與實現(xiàn)步驟的文章就介紹到這了,更多相關(guān)SpringBoot3 token攔截器鏈內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis Plus條件構(gòu)造器ConditionConstructor用法實例解析
這篇文章主要介紹了Mybatis Plus條件構(gòu)造器ConditionConstructor用法實例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-08-08
springboot內(nèi)置tomcat調(diào)優(yōu)并發(fā)線程數(shù)解析
這篇文章主要介紹了springboot內(nèi)置tomcat調(diào)優(yōu)并發(fā)線程數(shù)解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12
Java 11 正式發(fā)布,這 8 個逆天新特性教你寫出更牛的代碼
美國當?shù)貢r間9月25日,Oracle 官方宣布 Java 11 (18.9 LTS) 正式發(fā)布,可在生產(chǎn)環(huán)境中使用!這是自 Java 8 后的首個長期支持版本2018-09-09
SpringMVC中@Valid不起效BindingResult讀取不到Error信息
在寫SpringMVC項目時,由于要對表單數(shù)據(jù)進行校驗,需要使用@Valid進行校驗,但是在進行數(shù)據(jù)校驗時,BindingResult對象無法攔截非法表單數(shù)據(jù),result.hasErrors()無論怎么輸入都會返回false,本文詳細的介紹一下解決方法2021-09-09
IDEA的spring項目使用@Qualifier飄紅問題及解決
這篇文章主要介紹了IDEA的spring項目使用@Qualifier飄紅問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11

