Java中JWT令牌實(shí)現(xiàn)登錄驗(yàn)證
1.實(shí)現(xiàn)登錄驗(yàn)證的引出
傳統(tǒng)思路下:
- 登錄頁(yè)面把用戶名和密碼交給服務(wù)器。
- 服務(wù)器驗(yàn)證用戶名和密碼是否正確,并返回校驗(yàn)結(jié)果給后端。
- 如果密碼正確,就會(huì)在服務(wù)器創(chuàng)建Session,通過(guò)Cookie把sessionId返回給客戶端。
原因
但是在集群環(huán)境下,無(wú)法直接使用Session。因?yàn)槿绻徊渴鹪谝慌_(tái)機(jī)器時(shí),容易發(fā)生單點(diǎn)故障(一旦這臺(tái)服務(wù)器掛了,整個(gè)應(yīng)用就無(wú)法訪問(wèn)),所以通常情況下,一個(gè)Web應(yīng)用會(huì)部署在多個(gè)服務(wù)器上,通過(guò)Nginx等進(jìn)行負(fù)載均衡。此時(shí),來(lái)自一個(gè)用戶的請(qǐng)求就會(huì)分發(fā)到不同的服務(wù)器上。
- 使用Session時(shí):
用戶登錄: 用戶登錄請(qǐng)求,經(jīng)過(guò)負(fù)載均衡發(fā)送給服務(wù)器1,服務(wù)器1進(jìn)行用戶名和密碼驗(yàn)證,驗(yàn)證成功后,把Session存在了服務(wù)器1上。
查詢(xún)操作:用戶登錄之后,攜帶Cookie(里面帶有SessionId)繼續(xù)執(zhí)行查詢(xún)操作,假如進(jìn)行查詢(xún)博客列表,此時(shí)請(qǐng)求經(jīng)過(guò)負(fù)載均衡發(fā)到服務(wù)器2上,服務(wù)器2會(huì)先通過(guò)SessionId驗(yàn)證用戶是否登錄,此時(shí)第二臺(tái)機(jī)器上沒(méi)有該用戶的Session,即出現(xiàn)查詢(xún)不了的問(wèn)題。
2.JWT令牌
JWT全稱(chēng):JSON Web Token,用于客戶端和服務(wù)器之間傳遞安全可靠的信息,本質(zhì)是一個(gè)token,也叫token,令牌的本質(zhì)就是一個(gè)字符串。相當(dāng)于現(xiàn)在人們的身份證,出門(mén)在外驗(yàn)證身份的時(shí)候,拿出身份證即可。
2.1 使用JWT令牌時(shí)
- 用戶登錄 : 用戶登錄請(qǐng)求,經(jīng)過(guò)負(fù)載均衡,把請(qǐng)求發(fā)給服務(wù)器1,服務(wù)器1進(jìn)行賬號(hào)密碼驗(yàn)證,驗(yàn)證成功之后,生成一個(gè)令牌,并返回給客戶端。
- 客戶端收到令牌時(shí),把令牌存儲(chǔ)起來(lái),可以存儲(chǔ)在Cookie中,也可以存儲(chǔ)在其它的存儲(chǔ)空間,典型的如(localStorage)
- 查詢(xún)操作 用戶登錄之后,攜帶令牌繼續(xù)執(zhí)行查詢(xún)操作,假如查詢(xún)博客列表,此時(shí)請(qǐng)求經(jīng)過(guò)負(fù)載均衡發(fā)到服務(wù)器2,服務(wù)器2先進(jìn)行權(quán)限驗(yàn)證操作。服務(wù)器驗(yàn)證令牌是否有效,如果有效,說(shuō)明用戶已經(jīng)執(zhí)行了登錄操作,如果無(wú)效,說(shuō)明用戶之前未執(zhí)行登錄操作。
2.2 令牌的組成
令牌官網(wǎng)所示,token,本質(zhì)上一個(gè)字符串中間使用 符號(hào) 點(diǎn) . 來(lái)分割,令牌由三部分組成,header、payload和verify signature。
第一部分:Header(頭),令牌的類(lèi)型和使用的簽名算法,如"alg": “HS256(哈希算法)”, “typ”: “JWT”。
第二部分:Payload(負(fù)載),存放一些有效的信息(自定義信息,默認(rèn)信息)如{“id”:“1”,“username”:“zhangsan”},還存在JWT提供的現(xiàn)場(chǎng)字段,如過(guò)期時(shí)間戳等。
第三部分:Signature(簽名),防止token被篡改,確保安全性。
簽名的目的就是為了防止token被篡改,而正因?yàn)閠oken最后一個(gè)部分簽名存在, 所以整個(gè)token是非常安全可靠的,一旦token當(dāng)中的任何一部分被修改, 整個(gè)token在校驗(yàn)的時(shí)候都會(huì)失敗。
3. JWT令牌(token)生成和校驗(yàn)
3.1 引入JWT令牌的依賴(lài)
- 在pom.xml文件中引入依賴(lài)
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred --> <version>0.11.5</version> <scope>runtime</scope> </dependency>
3.2 使用Jar包中提供的API來(lái)實(shí)現(xiàn)JWT令牌的生成和校驗(yàn)
- 生成token之后,獲取token進(jìn)行解析,創(chuàng)建解釋器,設(shè)置簽名密鑰,如果解析token的claims內(nèi)容不為null,說(shuō)明校驗(yàn)成功,否則失敗。
package com.example.blog.utils; import com.example.blog.constant.Constants; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtParser; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.io.Decoders; import io.jsonwebtoken.io.Encoders; import io.jsonwebtoken.security.Keys; import lombok.extern.slf4j.Slf4j; import javax.crypto.SecretKey; import java.security.Key; import java.util.Date; import java.util.HashMap; import java.util.Map; @Slf4j public class JwtUtils { // JWT過(guò)期時(shí)間 public static final long JWT_EXPIRATION = 60*60*60*1000; // 生成key private static final String secretStr = "DuJXRS2W3AJHqyFhAplBmsPNawnEdFYFNmlNdMbyU9w="; private static final Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretStr)); /** * 生成token */ public static String genJwtToken(Map<String,Object> claim) { String token = Jwts.builder().setClaims(claim) .setExpiration(new Date(System.currentTimeMillis()+JWT_EXPIRATION)) .signWith(key) .compact(); return token; } /** * 校驗(yàn)token * Claims 為空,表示jwt校驗(yàn)失敗 * */ public static Claims parseToken(String token) { // 創(chuàng)建解析器,設(shè)置簽名密鑰 JwtParser build = Jwts.parserBuilder().setSigningKey(key).build(); Claims claims = null; try { // 解析token claims = build.parseClaimsJws(token).getBody(); }catch (Exception e){ log.error("解析token失敗,token:{}",token); return null; } return claims; } }
3.3 使用JWT令牌驗(yàn)證登錄
3.4 令牌的優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):
- 解決了集群環(huán)境下認(rèn)證的問(wèn)題
- 不需要在服務(wù)器端存儲(chǔ),從而減輕了服務(wù)器的存儲(chǔ)壓力
- 缺點(diǎn):
- 需要自己實(shí)現(xiàn)令牌的生成、傳遞、校驗(yàn)
到此這篇關(guān)于Java中JWT令牌實(shí)現(xiàn)登錄驗(yàn)證的文章就介紹到這了,更多相關(guān)Java JWT令牌登錄驗(yàn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中null相關(guān)注解的實(shí)現(xiàn)
本文主要介紹了Java中null相關(guān)注解的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04Java利用位運(yùn)算實(shí)現(xiàn)乘法運(yùn)算詳解
這篇文章主要為大家詳細(xì)介紹了Java如何用位運(yùn)算實(shí)現(xiàn)乘法運(yùn)算,在實(shí)現(xiàn)乘法時(shí)要用位運(yùn)算實(shí)現(xiàn),并且不能出現(xiàn)加減乘除任何符號(hào),感興趣的可以了解一下2023-04-04Springboot2.0配置JPA多數(shù)據(jù)源連接兩個(gè)mysql數(shù)據(jù)庫(kù)方式
這篇文章主要介紹了Springboot2.0配置JPA多數(shù)據(jù)源連接兩個(gè)mysql數(shù)據(jù)庫(kù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09Java Socket循環(huán)接收數(shù)據(jù)readLine()阻塞的解決方案
這篇文章主要介紹了Java Socket循環(huán)接收數(shù)據(jù)readLine()阻塞的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08Spring中PathMatcher路徑匹配器的實(shí)現(xiàn)
Spring框架中的PathMatcher是一個(gè)接口,本文主要介紹了Spring中PathMatcher路徑匹配器的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07使用jvisualvm配合Visual GC插件監(jiān)控Java程序詳細(xì)總結(jié)
本節(jié)將會(huì)介紹一下jvisualvm的特性及作用、各個(gè)功能是如何使用的、最后會(huì)介紹jvisualvm的插件Visual GC的安裝及使用2021-09-09