SpringBoot 整合 JWT 實現分佈式應用登錄校驗
什麼是 JWT?
JSON Web 令牌(JWT)是一個開放標準(RFC 7519),它定義了一種緊湊且自包含的方式,用於在各方之間安全地傳輸信息作爲 JSON 對象。由於此信息是經過數字簽名的,因此可以被驗證和信任。可以使用祕密(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公鑰 / 私鑰對對 JWT 進行簽名。
儘管可以對 JWT 進行加密以提供雙方之間的保密性,但我們將重點關注已_簽名的_令牌。簽名的令牌可以驗證其中包含的聲明的_完整性_,而加密的令牌則將這些聲明_隱藏_在其他方的面前。當使用公鑰 / 私鑰對對令牌進行簽名時,簽名還證明只有持有私鑰的一方纔是對其進行簽名的一方。
JWT 組成部分
header+payload+signature
-
頭部:主要是描述簽名算法
-
負載:主要描述是加密對象的信息,如用戶的 id 等,也可以加些規範裏面的東西,如 iss 簽發者,exp 過期時間,sub 面向的用戶
-
簽名:主要是把前面兩部分進行加密,防止別人拿到 token 進行 base 解密後篡改 token
JWT 優缺點
-
優點
-
生產的 token 可以包含基本信息,比如 id、用戶暱稱、頭像等信息,避免再次查庫
-
存儲在客戶端,不佔用服務端的內存資源
-
缺點
-
token 是經過 base64 編碼,所以可以解碼,因此 token 加密前的對象不應該包含敏感信息,如用戶權限,密碼等
-
如果沒有服務端存儲,則不能做登錄失效處理,除非服務端改祕鑰
SpringBoot 整合 JWT
1、添加相關依賴、
io.jsonwebtoken jjwt 0.7.0
2、封裝 JWT Utils 工具類
封裝生成 token 方法
`public static String geneJsonWebToken(LoginUser loginUser) {
if (loginUser == null) {
throw new NullPointerException("loginUser對象爲空");
}
Long userId = loginUser.getId();
String token = Jwts.builder().setSubject(SUBJECT)
.claim("head_img", loginUser.getHeadImg())
.claim("id", loginUser.getId())
.claim("name", loginUser.getName())
.claim("mail", loginUser.getMail())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET).compact();
token = TOKEN_PREFIX + token;
return token;
}
`
封裝解析 token 方法
public static Claims checkJwt(String token){ try { Claims claims = Jwts.parser() .setSigningKey(SECRET) .parseClaimsJws(token.replace(TOKEN_PREFIX, "")) .getBody(); return claims; } catch (Exception e) { log.info("jwt解密失敗,token={}",token,e.getMessage()); } return null; }
JWT 相關問題
JWT 過期自動刷新方案介紹
背景
-
在前後分離場景下,越來越多的項目使用 jwt token 作爲接口的安全機制, 但存在 jwt 過期後,用戶無法直接感知,假如在用戶操作頁面期間,突然提示登錄,則體驗很不友好,所以就有了 token 自動刷新需求
但是這個自動刷新方案,基本都離不開服務端狀態存儲,JWT 推出思想是:去中心化,無狀態化,所以有所違背。類似這樣的業務,有阿里雲首頁,沒有做 token 刷新令牌維護,但是符合對應的思想
解決方案
`用戶登錄成功的時候,一次性給他兩個Token,分別爲AccessToken和RefreshToken
AccessToken有效期較短,比如1天或者5天,用於正常請求
RefreshToken有效期可以設置長一些,例如10天、20天,作爲刷新AccessToken的憑證
刷新方案:當AccessToken即將過期的時候,例如提前30分鐘,客戶端利用RefreshToken請求指定的API獲取新的AccessToken並更新本地存儲中的AccessToken
核心邏輯
1、登錄成功後,jwt生成AccessToken;UUID生成RefreshToken並存儲在服務端redis中,設置過期時間
2、接口返回3個字段AccessToken/RefreshToken/訪問令牌過期時間戳
3、由於RefreshToken存儲在服務端redis中,假如這個RefreshToken也過期,則提示重新登錄;
老王的疑問:RefreshToken有效期那麼長,和直接將AccessToken的有效期延長有什麼區別
答:RefreshToken不像AccessToken那樣在大多數請求中都被使用,主要是本地檢測accessToken快過期的時候才使用,
一般本地存儲的時候,也不叫refreshToken,前端可以取個別名,混淆代碼讓攻擊者不能直接識別這個就是刷新令牌
缺點:前端每次請求需要判斷token距離過期時間
優點:後端壓力小,代碼邏輯改動不大
`
JWT 令牌 token 泄露惡意使用解決方案
解密:使用互聯網大廠的產品時經常遇到這個情況
-
比如阿里雲或者淘寶,你現在登錄瞭然後換個網絡或者地域就需要重新登錄
-
就是對應的 token 令牌,不只簡單的算法加密,還包括了客戶端屬性、地理網絡位置信息等,一起組成一個 token 令牌
如何避免 token 令牌泄露被惡意使用
-
ip 綁定方式
-
綁定瀏覽器 user-agent
解決方案
`生成token的時候,加密的payload加入當前用戶ip。
攔截器解密後,獲取payload的ip和當前訪問ip判斷是否同個,如果不是則提示重新登錄
優點:服務端無需存儲相關內容,性能高,假如用戶廣州登錄,泄露了token給杭州的黑客,依舊用不了
缺點:如果用戶用使用過程中ip變動頻繁,則操作會經常提示重新登錄,體驗不友好
當然也可以讓用戶開啓安全模式和非安全模式,讓用戶自己知道這個情況,一些區塊鏈、比特幣交易所裏面就會讓用戶自己選擇控制這個token令牌安全是否和ip、終端、地理網絡信息進行綁定
`
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/UlIIJBzpnHyfcRgyoFIeYQ