Java?JWT實(shí)現(xiàn)跨域身份驗(yàn)證方法詳解
1、JWT簡(jiǎn)介
JWT(JSON Web Token)是目前流行的跨域認(rèn)證解決方案,是一個(gè)開放標(biāo)準(zhǔn)(RFC 7519),它定義了一種緊湊的、自包含的方式,用于作為JSON對(duì)象在各方之間安全地傳輸信息。該信息可以被驗(yàn)證和信任,因?yàn)樗菙?shù)字簽名的。
2、JWT的結(jié)構(gòu)
JWT是由頭部(header)、載荷(payload)、簽證(signature)三段信息構(gòu)成的,將三段信息文本用"."連接在一起就構(gòu)成了JWT字符串。
例如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
使用在線校驗(yàn)工具(https://jwt.io/)將上述Token進(jìn)行解碼就可以看到數(shù)據(jù),如下圖所示
2.1 頭部(header)
JWT的頭部承載兩部分信息:
(1)聲明類型:這里主要是JWT。
(2)聲明加密算法:通常直接使用HMAC SHA256。
例如:
{ "alg": "HS256", "typ": "JWT" }
alg屬性表示簽名所使用的算法;
JWT簽名默認(rèn)的算法為HMAC SHA256;
alg屬性值HS256就是HMAC SHA256算法;
type屬性表示令牌類型,這里是JWT。
2.2 載荷(payload)
載荷是JWT的主體,同樣也是一個(gè)JSON對(duì)象。載荷包含三個(gè)部分:
(1)標(biāo)準(zhǔn)中的聲明(Registered Claims):一組預(yù)定義的聲明,不是強(qiáng)制的,但是推薦。
- iss(issuer):JWT簽發(fā)者
- sub(subject):JWT索所面向的用戶
- aud(audience):接收J(rèn)WT的一方
- exp(expiration):JWT的過期時(shí)間,必須要大于簽發(fā)時(shí)間。
- nbf(not before):定義了再什么時(shí)間之前該JWT都是不可用的。
- iat(issued at):JWT的發(fā)布時(shí)間,UNIX時(shí)間戳。
- jti(JWT ID):JWT的唯一ID編號(hào)。
(2)公共的聲明:可以添加任意信息,一般添加用戶的相關(guān)信息或其他業(yè)務(wù)需要的必要信息,但不建議添加敏感信息。
(3)私有的聲明:提供者和消費(fèi)者所共同定義的聲明,一般不建議存放敏感信息。
2.3 簽證(signature)
JWT的第三部分是一個(gè)簽證信息,由三部分組成:header(base64后的)、payload(base64后的)、secret(密鑰,需要保存好)。
例如:
HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)
簽名用于驗(yàn)證消息再傳遞過程中有沒有被更改,并且對(duì)于使用私鑰簽名的Token還可以驗(yàn)證JWT的發(fā)送方是否為它所說的發(fā)送方。
secret是保存在服務(wù)端的,JWT的簽發(fā)生成也是在服務(wù)端的,secret就是用來進(jìn)行JWT的簽發(fā)和驗(yàn)證的,所以secret是服務(wù)端的私鑰,在任何場(chǎng)景都不應(yīng)該流露出去。
3、JWT的原則
JWT的原則是在服務(wù)器身份驗(yàn)證之后,將生成一個(gè)JSON對(duì)象并將其發(fā)送回用戶,如下所示。
{ "sub": "1234567890", "name": "Helen", "admin": true }
之后,當(dāng)用戶與服務(wù)器通信時(shí),客戶在請(qǐng)求中發(fā)回JSON對(duì)象。服務(wù)器僅依賴于這個(gè)JSON對(duì)象來標(biāo)識(shí)用戶。為了防止用戶篡改數(shù)據(jù),服務(wù)器將在生成對(duì)象時(shí)添加簽名。
服務(wù)器不保存任何會(huì)話數(shù)據(jù),即服務(wù)器變?yōu)闊o狀態(tài),使其更容易擴(kuò)展。
4、JWT的用法
客戶端接收服務(wù)器返回的JWT,將其存儲(chǔ)在Cookie或localStorage中。
此后,客戶端將在與服務(wù)器交互中都會(huì)帶JWT。如果將它存儲(chǔ)在Cookie中,就可以自動(dòng)發(fā)送,但是不會(huì)跨域,因此一般是將它放入HTTP請(qǐng)求的Header Authorization字段中。當(dāng)跨域時(shí),也可以將JWT被放置于POST請(qǐng)求的數(shù)據(jù)主體中。
5、JWT的問題和趨勢(shì)
JWT不僅可用于認(rèn)證,還可用于信息交換。善用JWT有助于減少服務(wù)器請(qǐng)求數(shù)據(jù)庫(kù)的次數(shù)。
生產(chǎn)的token可以包含基本信息,比如id、用戶昵稱、頭像等信息,避免再次查庫(kù)
存儲(chǔ)在客戶端,不占用服務(wù)端的內(nèi)存資源
JWT默認(rèn)不加密,但可以加密。生成原始令牌后,可以再次對(duì)其進(jìn)行加密。
當(dāng)JWT未加密時(shí),一些私密數(shù)據(jù)無法通過JWT傳輸。
JWT的最大缺點(diǎn)是服務(wù)器不保存會(huì)話狀態(tài),所以在使用期間不可能取消令牌或更改令牌的權(quán)限。也就是說,一旦JWT簽發(fā),在有效期內(nèi)將會(huì)一直有效。
JWT本身包含認(rèn)證信息,token是經(jīng)過base64編碼,所以可以解碼,因此token加密前的對(duì)象不應(yīng)該包含敏感信息,一旦信息泄露,任何人都可以獲得令牌的所有權(quán)限。為了減少盜用,JWT的有效期不宜設(shè)置太長(zhǎng)。對(duì)于某些重要操作,用戶在使用時(shí)應(yīng)該每次都進(jìn)行進(jìn)行身份驗(yàn)證。
為了減少盜用和竊取,JWT不建議使用HTTP協(xié)議來傳輸代碼,而是使用加密的HTTPS協(xié)議進(jìn)行傳輸。
6、整合JWT令牌
6.1 在模塊中添加jwt工具依賴
<dependencies> <!-- JWT--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> </dependency> </dependencies>
6.2 創(chuàng)建JWT工具類
/** * JWT工具類 */ public class JwtHelper { //過期時(shí)間 private static long tokenExpiration = 24*60*60*1000; //token簽名密鑰 private static String tokenSignKey = "123456"; //根據(jù)參數(shù)生成token public static String createToken(Long userId, String userName) { String token = Jwts.builder() .setSubject("YYGH-USER") //設(shè)置過期時(shí)間 30分鐘 .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration)) //設(shè)置主題信息 用戶id和用戶名稱 .claim("userId", userId) .claim("userName", userName) //簽名哈希 .signWith(SignatureAlgorithm.HS512, tokenSignKey) .compressWith(CompressionCodecs.GZIP) .compact(); return token; } //根據(jù)token字符串得到用戶id public static Long getUserId(String token) { if(StringUtils.isEmpty(token)) return null; Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); Claims claims = claimsJws.getBody(); Integer userId = (Integer)claims.get("userId"); return userId.longValue(); } //根據(jù)token字符串得到用戶名稱 public static String getUserName(String token) { if(StringUtils.isEmpty(token)) return ""; Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token); Claims claims = claimsJws.getBody(); return (String)claims.get("userName"); } }
寫個(gè)主函數(shù)測(cè)試下:
public static void main(String[] args) { String token = JwtHelper.createToken(1L, "lucy"); System.out.println(token); System.out.println(JwtHelper.getUserId(token)); System.out.println(JwtHelper.getUserName(token)); }
簽發(fā)和解析都沒問題。
到此這篇關(guān)于Java JWT實(shí)現(xiàn)跨域身份驗(yàn)證方法詳解的文章就介紹到這了,更多相關(guān)JWT跨域身份驗(yàn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中LocalDate的詳細(xì)方法舉例總結(jié)
這篇文章主要給大家介紹了關(guān)于Java中LocalDate詳細(xì)方法舉例的相關(guān)資料,LocalDate主要是用來處理日期的類,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09BufferedWriter如何使用write方法實(shí)現(xiàn)換行
這篇文章主要介紹了BufferedWriter如何使用write方法實(shí)現(xiàn)換行的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07java生成申請(qǐng)單序列號(hào)的實(shí)現(xiàn)方法
申請(qǐng)單序列號(hào)一般要求根據(jù)一定的規(guī)則生成后幾位連續(xù)的字符串,下面是我項(xiàng)目中使用的生成序列號(hào)的代碼,其中用到了鎖機(jī)制,有需要的朋友可以參考一下2014-01-01Java實(shí)現(xiàn)導(dǎo)出word表格的示例詳解
這篇文章主要為大家詳細(xì)介紹了如何利用Java語言導(dǎo)出word表格功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的小伙伴可以參考一下2022-12-12Netty4之如何實(shí)現(xiàn)HTTP請(qǐng)求、響應(yīng)
這篇文章主要介紹了Netty4之如何實(shí)現(xiàn)HTTP請(qǐng)求、響應(yīng)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04Idea工具中創(chuàng)建 SpringBoot工程及入門詳解
這篇文章主要介紹了Idea工具中創(chuàng)建 SpringBoot工程及入門分析詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02