SpringBoot集成Auth0 JWT的示例代碼
前言
說(shuō)說(shuō)JWT,先說(shuō)下互聯(lián)網(wǎng)服務(wù)常見(jiàn)的兩種用戶認(rèn)證方式:
session認(rèn)證與Token認(rèn)證
session認(rèn)證
傳統(tǒng)的Session認(rèn)證的大體流程可以表示為用戶提供用戶名和密碼登錄后由服務(wù)器存儲(chǔ)一份用戶登錄信息并傳遞給瀏覽器保存為Cookie,并在下次請(qǐng)求中根據(jù)Cookie來(lái)識(shí)別用戶,但這種方式缺陷明顯:
- Session都是保存在內(nèi)存中,隨著認(rèn)證用戶的增多,服務(wù)端的開(kāi)銷(xiāo)明顯增大
- 保存在內(nèi)存中的Session限制了分布式的應(yīng)用
- Cookie容易被截獲偽造
Token認(rèn)證
Token 泛指身份驗(yàn)證時(shí)使用的令牌,Token鑒權(quán)機(jī)制從某些角度而言與Cookie是一個(gè)作用,其目的是讓后臺(tái)知道請(qǐng)求是來(lái)自于受信的客戶端,其通過(guò)實(shí)現(xiàn)了某種算法加密的Token字符串來(lái)完成鑒權(quán)工作,其優(yōu)點(diǎn)在于:
- 服務(wù)器不需要保存 Session 數(shù)據(jù)(無(wú)狀態(tài)),容易實(shí)現(xiàn)擴(kuò)展
- 有效避免Cookie被截獲引發(fā)的CSRF攻擊
- 可以存儲(chǔ)一些業(yè)務(wù)邏輯所必要的非敏感信息
- 便于傳輸,其構(gòu)成非常簡(jiǎn)單,字節(jié)占用小
JWT簡(jiǎn)介
JWT定義
JWT全稱為Json web token,也就是 Json 格式的 web token,可以這么理解:
Token // 個(gè)人證件
JWT // 個(gè)人身份證
JWT數(shù)據(jù)結(jié)構(gòu)
JWT由三段字符串組成,中間用.分隔,如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEsInNjb3BlIjo4LCJleHAiOjE3MTU3NDAyMjIsImlhdCI6MTYyOTM0MDIyMn0.wuRsF5wvLHbDF_21Pocas8SeXQ315rgBl6wm1LRL2bQ
JWT 的三個(gè)部分依次如下:
- Header(頭部)// Header 部分是一個(gè) JSON 對(duì)象,描述 JWT 的元數(shù)據(jù),通常是下面的樣子。
- Payload(負(fù)載)// Payload 部分是一個(gè) JSON 對(duì)象,用來(lái)存放實(shí)際需要傳遞的數(shù)據(jù)
- Signature(簽名)// Signature 部分是對(duì)前兩部分的簽名,防止數(shù)據(jù)篡改
第一段字符串Header:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
將其 Base64 解碼后得到:
{ "typ": "JWT", // TOKEN TYPE ,token類(lèi)型 "alg": "HS256" //ALGORITHM,算法 哈希256 }
第二段字符串Payload:eyJ1aWQiOjEsInNjb3BlIjo4LCJleHAiOjE3MTU3NDAyMjIsImlhdCI6MTYyOTM0MDIyMn0
PAYLOAD是數(shù)據(jù)載體,可以有自定義數(shù)據(jù)
{ "uid": "1234567890" // 自定義數(shù)據(jù) }
第三段字符串Signature:wuRsF5wvLHbDF_21Pocas8SeXQ315rgBl6wm1LRL2bQ
Signature 部分是對(duì)前兩部分的簽名,防止數(shù)據(jù)篡改。
JWT的類(lèi)庫(kù)
Java 中的 JWT 有很多類(lèi)庫(kù),關(guān)于其優(yōu)缺點(diǎn)可以在官網(wǎng)查看:https://jwt.io/,這里我們介紹Auth0的JWT的集成使用方式
Auth0 實(shí)現(xiàn)的 com.auth0 / java-jwt / 3.3.0
Brian Campbell 實(shí)現(xiàn)的 org.bitbucket.b_c / jose4j / 0.6.3
connect2id 實(shí)現(xiàn)的 com.nimbusds / nimbus-jose-jwt / 5.7
Les Hazlewood 實(shí)現(xiàn)的 io.jsonwebtoken / jjwt / 0.9.0
FusionAuth 實(shí)現(xiàn)的 io.fusionauth / fusionauth-jwt / 3.1.0
Vert.x 實(shí)現(xiàn)的 io.vertx / vertx-auth-jwt / 3.5.1
具體實(shí)現(xiàn)
JWT配置
pom.xml
<!-- jwt --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.8.1</version> </dependency>
application.yml
coisini: security: jwt-key: coisini # 過(guò)期時(shí)間 token-expired-in: 86400000
JWT工具類(lèi)
JwtUtil.java
import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.*; /** * @Description JWT工具類(lèi) * @author coisini * @date Aug 18, 2021 * @Version 1.0 */ @Component public class JwtUtil { /** * key */ private static String jwtKey; /** * 過(guò)期時(shí)間 */ private static Integer expiredTimeIn; /** * JWT KEY * @param jwtKey */ @Value("${coisini.security.jwt-key}") public void setJwtKey(String jwtKey) { JwtUtil.jwtKey = jwtKey; } /** * 過(guò)期時(shí)間 * @param expiredTimeIn */ @Value("${coisini.security.token-expired-in}") public void setExpiredTimeIn(Integer expiredTimeIn) { JwtUtil.expiredTimeIn = expiredTimeIn; } /** * 生成令牌 * @param uid 用戶id * @return */ public static String makeToken(Long uid) { return JwtUtil.getToken(uid); } /** * 獲取令牌 * @param uid 用戶id * @param scope 權(quán)限分級(jí)數(shù)字 * @return */ private static String getToken(Long uid) { // 指定算法 Algorithm algorithm = Algorithm.HMAC256(JwtUtil.jwtKey); Map<String, Date> dateMap = JwtUtil.calculateExpiredIssues(); /** * withClaim() 寫(xiě)入自定義數(shù)據(jù) * withExpiresAt() 設(shè)置過(guò)期時(shí)間 * withIssuedAt() 設(shè)置當(dāng)前時(shí)間 * sign() 簽名算法 */ return JWT.create() .withClaim("uid", uid) .withExpiresAt(dateMap.get("expiredTime")) .withIssuedAt(dateMap.get("now")) .sign(algorithm); } /** * 獲取自定義數(shù)據(jù) * @param token * @return */ public static Optional<Map<String, Claim>> getClaims(String token) { DecodedJWT decodedJWT; // 指定算法 Algorithm algorithm = Algorithm.HMAC256(JwtUtil.jwtKey); JWTVerifier jwtVerifier = JWT.require(algorithm).build(); try { decodedJWT = jwtVerifier.verify(token); } catch (JWTVerificationException e) { return Optional.empty(); } return Optional.of(decodedJWT.getClaims()); } /** * 驗(yàn)證Token * @param token * @return */ public static boolean verifyToken(String token) { try { Algorithm algorithm = Algorithm.HMAC256(JwtUtil.jwtKey); JWTVerifier jwtVerifier = JWT.require(algorithm).build(); jwtVerifier.verify(token); } catch (JWTVerificationException e) { return false; } return true; } /** * 計(jì)算過(guò)期時(shí)間 * @return */ private static Map<String, Date> calculateExpiredIssues() { Map<String, Date> map = new HashMap<>(); Calendar calendar = Calendar.getInstance(); Date now = calendar.getTime(); calendar.add(Calendar.SECOND, JwtUtil.expiredTimeIn); // 當(dāng)前時(shí)間 map.put("now", now); // 過(guò)期時(shí)間 map.put("expiredTime", calendar.getTime()); return map; } }
測(cè)試接口
JwtController.java
@RestController @RequestMapping("/jwt") public class JwtController { /** * 獲取Token * @param id * @return */ @GetMapping(value = "/get") public String getToken(@RequestParam Long id) { return JwtUtil.makeToken(id); } /** * 驗(yàn)證Token * @param token * @return */ @PostMapping("/verify") public Map<String, Boolean> verify(@RequestParam String token) { Map<String, Boolean> map = new HashMap<>(); Boolean valid = JwtUtil.verifyToken(token); map.put("is_valid", valid); return map; } }
測(cè)試結(jié)果
JWT生成的Token應(yīng)該放在請(qǐng)求頭內(nèi)來(lái)傳輸,后端統(tǒng)一攔截驗(yàn)證,這里留在下篇文章吧。。。
到此這篇關(guān)于SpringBoot集成Auth0 JWT的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot集成Auth0 JWT內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot+Spring Security+JWT實(shí)現(xiàn)RESTful Api權(quán)限控制的方法
- SpringBoot整合SpringSecurity和JWT的示例
- SpringBoot集成JWT實(shí)現(xiàn)token驗(yàn)證的流程
- spring boot如何基于JWT實(shí)現(xiàn)單點(diǎn)登錄詳解
- 基于springboot+jwt實(shí)現(xiàn)刷新token過(guò)程解析
- SpringBoot集成JWT生成token及校驗(yàn)方法過(guò)程解析
- SpringBoot使用JWT實(shí)現(xiàn)登錄驗(yàn)證的方法示例
- Spring-boot結(jié)合Shrio實(shí)現(xiàn)JWT的方法
- 在SpringBoot中使用JWT的實(shí)現(xiàn)方法
相關(guān)文章
關(guān)于intellij idea打開(kāi)就閃退或關(guān)閉詳細(xì)解決辦法
這篇文章主要介紹了關(guān)于intellij idea打開(kāi)就閃退或關(guān)閉詳細(xì)解決辦法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03java實(shí)現(xiàn)在性能測(cè)試中進(jìn)行業(yè)務(wù)驗(yàn)證實(shí)例
這篇文章主要為大家介紹了java實(shí)現(xiàn)在性能測(cè)試中進(jìn)行業(yè)務(wù)驗(yàn)證實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07Java的內(nèi)存區(qū)域與內(nèi)存溢出異常你了解嗎
這篇文章主要為大家詳細(xì)介紹了Java的內(nèi)存區(qū)域與內(nèi)存溢出異常,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03mybatis簡(jiǎn)介與配置_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了mybatis簡(jiǎn)介與配置,介紹了MyBatis+Spring+MySql簡(jiǎn)單配置,有興趣的可以了解一下2017-09-09如何基于Springboot完成新增員工功能并設(shè)置全局異常處理器
最近工作中遇到了做一個(gè)管理員工信息的功能,下面這篇文章主要給大家介紹了關(guān)于如何基于Springboot完成新增員工功能并設(shè)置全局異常處理器的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11java數(shù)字圖像處理基礎(chǔ)使用imageio寫(xiě)圖像文件示例
這篇文章主要介紹了Java 2D的圖像處理API,文章討論和提及的API都是基于JDK6的,Java中寫(xiě)一個(gè)圖像文件使用ImageIO對(duì)象即可,下面看代碼吧2014-01-01詳解Eclipse 字體、字號(hào)的設(shè)置、最佳字體推薦
這篇文章主要介紹了Eclipse 字體、字號(hào)的設(shè)置、最佳字體推薦,需要的朋友可以參考下2020-09-09Java實(shí)現(xiàn)購(gòu)物管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)購(gòu)物管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01