SpringBoot中過濾器Filter+JWT令牌實(shí)現(xiàn)登錄驗(yàn)證
登錄校驗(yàn)-Filter
分析
過濾器Filter的快速入門以及使用細(xì)節(jié)我們已經(jīng)介紹完了,接下來最后一步,我們需要使用過濾器Filter來完成案例當(dāng)中的登錄校驗(yàn)功能。

我們先來回顧下前面分析過的登錄校驗(yàn)的基本流程:
要進(jìn)入到后臺管理系統(tǒng),我們必須先完成登錄操作,此時就需要訪問登錄接口login。
登錄成功之后,我們會在服務(wù)端生成一個JWT令牌,并且把JWT令牌返回給前端,前端會將JWT令牌存儲下來。
在后續(xù)的每一次請求當(dāng)中,都會將JWT令牌攜帶到服務(wù)端,請求到達(dá)服務(wù)端之后,要想去訪問對應(yīng)的業(yè)務(wù)功能,此時我們必須先要校驗(yàn)令牌的有效性。
對于校驗(yàn)令牌的這一塊操作,我們使用登錄校驗(yàn)的過濾器,在過濾器當(dāng)中來校驗(yàn)令牌的有效性。如果令牌是無效的,就響應(yīng)一個錯誤的信息,也不會再去放行訪問對應(yīng)的資源了。如果令牌存在,并且它是有效的,此時就會放行去訪問對應(yīng)的web資源,執(zhí)行相應(yīng)的業(yè)務(wù)操作。
大概清楚了在Filter過濾器的實(shí)現(xiàn)步驟了,那在正式開發(fā)登錄校驗(yàn)過濾器之前,我們思考兩個問題:
所有的請求,攔截到了之后,都需要校驗(yàn)令牌嗎?
- 答案:登錄請求例外
攔截到請求后,什么情況下才可以放行,執(zhí)行業(yè)務(wù)操作?
- 答案:有令牌,且令牌校驗(yàn)通過(合法);否則都返回未登錄錯誤結(jié)果
具體流程
我們要完成登錄校驗(yàn),主要是利用Filter過濾器實(shí)現(xiàn),而Filter過濾器的流程步驟:

基于上面的業(yè)務(wù)流程,我們分析出具體的操作步驟:
- 獲取請求url
- 判斷請求url中是否包含login,如果包含,說明是登錄操作,放行
- 獲取請求頭中的令牌(token)
- 判斷令牌是否存在,如果不存在,返回錯誤結(jié)果(未登錄)
- 解析token,如果解析失敗,返回錯誤結(jié)果(未登錄)
- 放行
代碼實(shí)現(xiàn)
分析清楚了以上的問題后,我們就參照接口文檔來開發(fā)登錄功能了,登錄接口描述如下:
請求參數(shù)
參數(shù)格式:application/json
參數(shù)說明:
| 名稱 | 類型 | 是否必須 | 備注 |
|---|---|---|---|
| username | string | 必須 | 用戶名 |
| password | string | 必須 | 密碼 |
請求數(shù)據(jù)樣例:
{
"username": "jinyong",
"password": "123456"
}
響應(yīng)數(shù)據(jù)
參數(shù)格式:application/json
參數(shù)說明:
| 名稱 | 類型 | 是否必須 | 默認(rèn)值 | 備注 | 其他信息 |
|---|---|---|---|---|---|
| code | number | 必須 | 響應(yīng)碼, 1 成功 ; 0 失敗 | ||
| msg | string | 非必須 | 提示信息 | ||
| data | string | 必須 | 返回的數(shù)據(jù) , jwt令牌 |
響應(yīng)數(shù)據(jù)樣例:
{
"code": 1,
"msg": "success",
"data": "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojfrr6XMJ-yVzaWCVZCo"
}
備注說明
用戶登錄成功后,系統(tǒng)會自動下發(fā)JWT令牌,然后在后續(xù)的每次請求中,都需要在請求頭header中攜帶到服務(wù)端,請求頭的名稱為 token ,值為 登錄時下發(fā)的JWT令牌。
如果檢測到用戶未登錄,則會返回如下固定錯誤信息:
{
"code": 0,
"msg": "NOT_LOGIN",
"data": null
}
登錄校驗(yàn)過濾器:LoginCheckFilter
@Slf4j
@WebFilter(urlPatterns = "/*") //攔截所有請求
public class LoginCheckFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
//前置:強(qiáng)制轉(zhuǎn)換為http協(xié)議的請求對象、響應(yīng)對象 (轉(zhuǎn)換原因:要使用子類中特有方法)
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
//1.獲取請求url
String url = request.getRequestURL().toString();
log.info("請求路徑:{}", url); //請求路徑:http://localhost:8080/login
//2.判斷請求url中是否包含login,如果包含,說明是登錄操作,放行
if(url.contains("/login")){
chain.doFilter(request, response);//放行請求
return;//結(jié)束當(dāng)前方法的執(zhí)行
}
//3.獲取請求頭中的令牌(token)
String token = request.getHeader("token");
log.info("從請求頭中獲取的令牌:{}",token);
//4.判斷令牌是否存在,如果不存在,返回錯誤結(jié)果(未登錄)
if(!StringUtils.hasLength(token)){
log.info("Token不存在");
Result responseResult = Result.error("NOT_LOGIN");
//把Result對象轉(zhuǎn)換為JSON格式字符串 (fastjson是阿里巴巴提供的用于實(shí)現(xiàn)對象和json的轉(zhuǎn)換工具類)
String json = JSONObject.toJSONString(responseResult);
response.setContentType("application/json;charset=utf-8");
//響應(yīng)
response.getWriter().write(json);
return;
}
//5.解析token,如果解析失敗,返回錯誤結(jié)果(未登錄)
try {
JwtUtils.parseJWT(token);
}catch (Exception e){
log.info("令牌解析失敗!");
Result responseResult = Result.error("NOT_LOGIN");
//把Result對象轉(zhuǎn)換為JSON格式字符串 (fastjson是阿里巴巴提供的用于實(shí)現(xiàn)對象和json的轉(zhuǎn)換工具類)
String json = JSONObject.toJSONString(responseResult);
response.setContentType("application/json;charset=utf-8");
//響應(yīng)
response.getWriter().write(json);
return;
}
//6.放行
chain.doFilter(request, response);
}
}
JWT導(dǎo)入的maven依賴
<!--JWT令牌-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
JWT的工具類
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;
public class JwtUtils {
private static String signKey = "shisan";
private static Long expire = 43200000L;
/**
* 生成JWT令牌
* @param claims JWT第二部分負(fù)載 payload 中存儲的內(nèi)容
* @return
*/
public static String generateJwt(Map<String, Object> 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第二部分負(fù)載 payload 中存儲的內(nèi)容
*/
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser()
.setSigningKey(signKey)
.parseClaimsJws(jwt)
.getBody();
return claims;
}
}
在上述過濾器的功能實(shí)現(xiàn)中,我們使用到了一個第三方j(luò)son處理的工具包fastjson。我們要想使用,需要引入如下依賴:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
登錄校驗(yàn)的過濾器我們編寫完成了,接下來我們就可以重新啟動服務(wù)來做一個測試:
測試前先把之前所編寫的測試使用的過濾器,暫時注釋掉。直接將@WebFilter注解給注釋掉即可。
測試1:未登錄是否可以訪問部門管理頁面
首先關(guān)閉瀏覽器,重新打開瀏覽器,在地址欄中輸入:http://localhost:9528/#/system/dept
由于用戶沒有登錄,登錄校驗(yàn)過濾器返回錯誤信息,前端頁面根據(jù)返回的錯誤信息結(jié)果,自動跳轉(zhuǎn)到登錄頁面了

測試2:先進(jìn)行登錄操作,再訪問部門管理頁面
登錄校驗(yàn)成功之后,可以正常訪問相關(guān)業(yè)務(wù)操作頁面

總結(jié): 這個過濾器檢查請求的URL是否包含 “login”。如果包含,則直接允許請求繼續(xù)。如果不包含 “login”,則檢查JWT令牌的存在和有效性。如果令牌不存在或無效,返回一個JSON格式的 “NOT_LOGIN” 錯誤響應(yīng)。如果令牌存在并且有效,則允許請求繼續(xù)。
到此這篇關(guān)于SpringBoot-過濾器Filter+JWT令牌實(shí)現(xiàn)登錄驗(yàn)證的文章就介紹到這了,更多相關(guān)SpringBoot 登錄驗(yàn)證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
FastJson時間格式化問題避坑經(jīng)驗(yàn)分享
這篇文章主要為大家介紹了FastJson時間格式化問題避坑經(jīng)驗(yàn)分享,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
SpringBoot接收請求參數(shù)的四種方式總結(jié)
這篇文章主要給大家介紹了關(guān)于SpringBoot接收請求參數(shù)的四種方式,文中通過代碼以及圖文介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用SpringBoot具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09
線程池ThreadPoolExecutor使用簡介與方法實(shí)例
今天小編就為大家分享一篇關(guān)于線程池ThreadPoolExecutor使用簡介與方法實(shí)例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03
springboot jta atomikos實(shí)現(xiàn)分布式事物管理
這篇文章主要介紹了springboot jta atomikos實(shí)現(xiàn)分布式事物管理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
spring-boot報(bào)錯javax.servlet.http不存在的問題解決
當(dāng)springboot項(xiàng)目從2.7.x的升級到3.0.x的時候,會遇到j(luò)avax.servlet.http不存在,本文就來介紹一下這個問題的解決,具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06
java后臺利用Apache poi 生成excel文檔提供前臺下載示例
本篇文章主要介紹了java后臺利用Apache poi 生成excel文檔提供前臺下載示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-05-05

