JSON Web Token在登陸中的使用過(guò)程
JWT(JSON Web Token)是一種開(kāi)放標(biāo)準(zhǔn)(RFC 7519),用于在網(wǎng)絡(luò)應(yīng)用環(huán)境間安全地傳遞聲明。它的主要用途是身份驗(yàn)證和信息交換。
在微服務(wù)架構(gòu)中,JWT 作為認(rèn)證機(jī)制非常常見(jiàn),特別是與 API 網(wǎng)關(guān)結(jié)合使用時(shí)。
JWT 介紹
JWT 是由三部分組成的:
- Header(頭部):通常包含簽名的算法信息(例如 HMAC SHA256 或 RSA)。
- Payload(負(fù)載):包含聲明(Claims)。聲明可以是關(guān)于實(shí)體(通常是用戶)的信息,或者元數(shù)據(jù)。JWT 的負(fù)載部分是 base64 編碼的。
- Signature(簽名):簽名是用來(lái)驗(yàn)證 JWT 數(shù)據(jù)是否被篡改的。它通過(guò)將 header 和 payload 使用私鑰加密生成,確保 JWT 的數(shù)據(jù)安全性和完整性。
微服務(wù)架構(gòu)中的 JWT 使用
在微服務(wù)架構(gòu)中,多個(gè)微服務(wù)通常會(huì)通過(guò) HTTP 請(qǐng)求進(jìn)行交互。如果沒(méi)有合適的認(rèn)證機(jī)制,用戶的身份驗(yàn)證信息可能會(huì)在多個(gè)服務(wù)之間重復(fù)驗(yàn)證,這不但增加了冗余,也降低了安全性。
JWT 在這種情況下非常有用,因?yàn)樗茉谟脩舻卿洉r(shí)生成一個(gè)有效的 token,該 token 可以在不同的服務(wù)之間傳遞,而不需要每個(gè)服務(wù)都進(jìn)行用戶認(rèn)證。
結(jié)合微服務(wù)網(wǎng)關(guān)的 JWT 驗(yàn)證
微服務(wù)網(wǎng)關(guān)(如 Spring Cloud Gateway 或 Nginx)在微服務(wù)架構(gòu)中起到了流量管理、路由、負(fù)載均衡等作用。
JWT 與微服務(wù)網(wǎng)關(guān)結(jié)合時(shí),網(wǎng)關(guān)通常扮演驗(yàn)證用戶身份的角色。
具體的流程如下:
流程示例
- 用戶登錄:用戶通過(guò)用戶名和密碼登錄。后端服務(wù)會(huì)驗(yàn)證這些憑證,如果驗(yàn)證成功,則生成一個(gè) JWT token 返回給前端。
- 前端保存 JWT:前端將 JWT 保存在客戶端(如 localStorage 或 sessionStorage),并在后續(xù)的 API 請(qǐng)求中將其添加到 HTTP 請(qǐng)求的 Authorization 頭中。
- 微服務(wù)網(wǎng)關(guān)驗(yàn)證 JWT:用戶在每次請(qǐng)求時(shí)會(huì)將 JWT 發(fā)送到微服務(wù)網(wǎng)關(guān)。網(wǎng)關(guān)會(huì)驗(yàn)證 JWT 的有效性、簽名、過(guò)期時(shí)間等。如果 JWT 合法,則網(wǎng)關(guān)將請(qǐng)求轉(zhuǎn)發(fā)給目標(biāo)微服務(wù)。
- 微服務(wù)接收請(qǐng)求:微服務(wù)通過(guò)網(wǎng)關(guān)接收到請(qǐng)求時(shí),已經(jīng)可以信任這個(gè)用戶的身份,無(wú)需再進(jìn)行身份驗(yàn)證。微服務(wù)可以從 JWT 的 Payload 中提取用戶信息來(lái)處理請(qǐng)求。
1. 用戶登錄,生成 JWT
public class JwtUtil { private static final String SECRET_KEY = "secret"; // 用于加密的秘鑰 // 生成 JWT public static String createJWT(String userName) { return Jwts.builder() .setSubject(userName) .setIssuedAt(new Date()) // 設(shè)置發(fā)放時(shí)間 .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 設(shè)置過(guò)期時(shí)間,1小時(shí) .signWith(SignatureAlgorithm.HS256, SECRET_KEY) // 使用 HMAC-SHA256 加密 .compact(); } // 解析 JWT public static Claims parseJWT(String jwt) { return Jwts.parser() .setSigningKey(SECRET_KEY) .parseClaimsJws(jwt) .getBody(); } }
2. 自定義過(guò)濾器來(lái)實(shí)現(xiàn) JWT 的驗(yàn)證
@Component public class JwtAuthenticationFilter implements GatewayFilter, Ordered { private static final String AUTHORIZATION_HEADER = "Authorization"; @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String token = exchange.getRequest().getHeaders().getFirst(AUTHORIZATION_HEADER); if (token == null || !token.startsWith("Bearer ")) { return Mono.error(new RuntimeException("Unauthorized")); } try { String jwt = token.substring(7); // 去掉 "Bearer " 前綴 Claims claims = JwtUtil.parseJWT(jwt); // 解析 JWT // 可以根據(jù)解析的 claims 來(lái)做進(jìn)一步的驗(yàn)證或設(shè)置安全上下文 exchange.getRequest().mutate() .header("User", claims.getSubject()) // 在請(qǐng)求頭中設(shè)置用戶信息 .build(); } catch (Exception e) { return Mono.error(new RuntimeException("Invalid token")); } return chain.filter(exchange); // 繼續(xù)處理請(qǐng)求 } @Override public int getOrder() { return -1; // 優(yōu)先級(jí),越小越優(yōu)先 } }
3. 微服務(wù)中使用 JWT 數(shù)據(jù)
微服務(wù)從網(wǎng)關(guān)接收到請(qǐng)求時(shí),可以直接從請(qǐng)求頭中讀取用戶信息:
@RestController @RequestMapping("/user") public class UserController { @GetMapping("/info") public String getUserInfo(@RequestHeader("User") String userName) { // 使用 userName 獲取用戶信息 return "Hello, " + userName; } }
總結(jié)
通過(guò)將 JWT 和微服務(wù)網(wǎng)關(guān)結(jié)合使用,可以實(shí)現(xiàn)分布式系統(tǒng)中的統(tǒng)一身份驗(yàn)證。用戶登錄時(shí)通過(guò) JWT 獲取認(rèn)證信息,網(wǎng)關(guān)負(fù)責(zé)驗(yàn)證 JWT 的有效性和用戶身份,然后將請(qǐng)求轉(zhuǎn)發(fā)到對(duì)應(yīng)的微服務(wù)。微服務(wù)無(wú)需再驗(yàn)證用戶身份,只需要從 JWT 中提取必要的用戶信息進(jìn)行業(yè)務(wù)處理。
這種方式有效地減少了重復(fù)認(rèn)證的開(kāi)銷(xiāo),同時(shí)提高了系統(tǒng)的安全性和可擴(kuò)展性。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解SpringBoot 應(yīng)用如何提高服務(wù)吞吐量
這篇文章主要介紹了Spring Boot 應(yīng)用如何提高服務(wù)吞吐量,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07Java面向?qū)ο缶幊蹋ǚ庋b/繼承/多態(tài))實(shí)例解析
這篇文章主要介紹了Java面向?qū)ο缶幊蹋ǚ庋b/繼承/多態(tài))實(shí)例解析的相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可以了解下。2017-10-10Java Web項(xiàng)目中編寫(xiě)定時(shí)任務(wù)的實(shí)現(xiàn)
本篇文章主要介紹了Java Web項(xiàng)目中編寫(xiě)定時(shí)任務(wù)的實(shí)現(xiàn),具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01Java序列化中子類(lèi)、父類(lèi)構(gòu)造函數(shù)問(wèn)題實(shí)例分析
這篇文章主要介紹了Java序列化中子類(lèi)、父類(lèi)構(gòu)造函數(shù)問(wèn)題,結(jié)合實(shí)例形式分析了java父類(lèi)與子類(lèi)構(gòu)造函數(shù)中序列化接口調(diào)用相關(guān)操作技巧與使用注意事項(xiàng),需要的朋友可以參考下2019-09-09Java使用fill()數(shù)組填充的實(shí)現(xiàn)
這篇文章主要介紹了Java使用fill()數(shù)組填充的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01java實(shí)現(xiàn)基于UDP協(xié)議的聊天小程序操作
UDP是與TCP相對(duì)應(yīng)的協(xié)議,UDP適用于一次只傳送少量數(shù)據(jù)、對(duì)可靠性要求不高的應(yīng)用環(huán)境。正因?yàn)閁DP協(xié)議沒(méi)有連接的過(guò)程,所以它的通信效率高;但也正因?yàn)槿绱?,它的可靠性不如TCP協(xié)議高,本文給大家介紹java實(shí)現(xiàn)基于UDP協(xié)議的聊天小程序操作,感興趣的朋友一起看看吧2021-10-10Java從內(nèi)存角度帶你理解數(shù)組名實(shí)質(zhì)是個(gè)地址的論述
這篇文章主要介紹了Java如何從內(nèi)存解析的角度理解“數(shù)組名實(shí)質(zhì)是一個(gè)地址”,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2022-09-09mybaties?plus?selectMaps和selectList的區(qū)別說(shuō)明
這篇文章主要介紹了mybaties?plus?selectMaps和selectList的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12