golang jwt设置过期_听说你的JWT库用起来特别扭,推荐这款贼好用的!
以前一直使用的是jjwt這個JWT庫,雖然小巧夠用, 但對JWT的一些細節封裝的不是很好。最近發現了一個更好用的JWT庫nimbus-jose-jwt,簡單易用,API非常易于理解,對稱加密和非對稱加密算法都支持,推薦給大家!
簡介
nimbus-jose-jwt是最受歡迎的JWT開源庫,基于Apache 2.0開源協議,支持所有標準的簽名(JWS)和加密(JWE)算法。
JWT概念關系
這里我們需要了解下JWT、JWS、JWE三者之間的關系,其實JWT(JSON Web Token)指的是一種規范,這種規范允許我們使用JWT在兩個組織之間傳遞安全可靠的信息。而JWS(JSON Web Signature)和JWE(JSON Web Encryption)是JWT規范的兩種不同實現,我們平時最常使用的實現就是JWS。
使用
接下來我們將介紹下nimbus-jose-jwt庫的使用,主要使用對稱加密(HMAC)和非對稱加密(RSA)兩種算法來生成和解析JWT令牌。
對稱加密(HMAC)
對稱加密指的是使用相同的秘鑰來進行加密和解密,如果你的秘鑰不想暴露給解密方,考慮使用非對稱加密。
- 要使用nimbus-jose-jwt庫,首先在pom.xml添加相關依賴;
<dependency>
????<groupId>com.nimbusdsgroupId>
????<artifactId>nimbus-jose-jwtartifactId>
????<version>8.16version>
dependency>
- 創建JwtTokenServiceImpl作為JWT處理的業務類,添加根據HMAC算法生成和解析JWT令牌的方法,可以發現nimbus-jose-jwt庫操作JWT的API非常易于理解;
?*?Created?by?macro?on?2020/6/22.
?*/
@Service
public?class?JwtTokenServiceImpl?implements?JwtTokenService?{
????@Override
????public?String?generateTokenByHMAC(String?payloadStr,?String?secret)?throws?JOSEException?{
????????//創建JWS頭,設置簽名算法和類型
????????JWSHeader?jwsHeader?=?new?JWSHeader.Builder(JWSAlgorithm.HS256).
????????????????type(JOSEObjectType.JWT)
????????????????.build();
????????//將負載信息封裝到Payload中
????????Payload?payload?=?new?Payload(payloadStr);
????????//創建JWS對象
????????JWSObject?jwsObject?=?new?JWSObject(jwsHeader,?payload);
????????//創建HMAC簽名器
????????JWSSigner?jwsSigner?=?new?MACSigner(secret);
????????//簽名
????????jwsObject.sign(jwsSigner);
????????return?jwsObject.serialize();
????}
????@Override
????public?PayloadDto?verifyTokenByHMAC(String?token,?String?secret)?throws?ParseException,?JOSEException?{
????????//從token中解析JWS對象
????????JWSObject?jwsObject?=?JWSObject.parse(token);
????????//創建HMAC驗證器
????????JWSVerifier?jwsVerifier?=?new?MACVerifier(secret);
????????if?(!jwsObject.verify(jwsVerifier))?{
????????????throw?new?JwtInvalidException("token簽名不合法!");
????????}
????????String?payload?=?jwsObject.getPayload().toString();
????????PayloadDto?payloadDto?=?JSONUtil.toBean(payload,?PayloadDto.class);
????????if?(payloadDto.getExp()?new?Date().getTime())?{
????????????throw?new?JwtExpiredException("token已過期!");
????????}
????????return?payloadDto;
????}
}
- 創建PayloadDto實體類,用于封裝JWT中存儲的信息;
?*?Created?by?macro?on?2020/6/22.
?*/
@Data
@EqualsAndHashCode(callSuper?=?false)
@Builder
public?class?PayloadDto?{
????@ApiModelProperty("主題")
????private?String?sub;
????@ApiModelProperty("簽發時間")
????private?Long?iat;
????@ApiModelProperty("過期時間")
????private?Long?exp;
????@ApiModelProperty("JWT的ID")
????private?String?jti;
????@ApiModelProperty("用戶名稱")
????private?String?username;
????@ApiModelProperty("用戶擁有的權限")
????private?List?authorities;
}
- 在JwtTokenServiceImpl類中添加獲取默認的PayloadDto的方法,JWT過期時間設置為60min;
?*?Created?by?macro?on?2020/6/22.
?*/
@Service
public?class?JwtTokenServiceImpl?implements?JwtTokenService?{
????@Override
????public?PayloadDto?getDefaultPayloadDto()?{
????????Date?now?=?new?Date();
????????Date?exp?=?DateUtil.offsetSecond(now,?60*60);
????????return?PayloadDto.builder()
????????????????.sub("macro")
????????????????.iat(now.getTime())
????????????????.exp(exp.getTime())
????????????????.jti(UUID.randomUUID().toString())
????????????????.username("macro")
????????????????.authorities(CollUtil.toList("ADMIN"))
????????????????.build();
????}
}
- 創建JwtTokenController類,添加根據HMAC算法生成和解析JWT令牌的接口,由于HMAC算法需要長度至少為32個字節的秘鑰,所以我們使用MD5加密下;
?*?JWT令牌管理Controller
?*?Created?by?macro?on?2020/6/22.
?*/
@Api(tags?=?"JwtTokenController",?description?=?"JWT令牌管理")
@Controller
@RequestMapping("/token")
public?class?JwtTokenController?{
????@Autowired
????private?JwtTokenService?jwtTokenService;
????@ApiOperation("使用對稱加密(HMAC)算法生成token")
????@RequestMapping(value?=?"/hmac/generate",?method?=?RequestMethod.GET)
????@ResponseBody
????public?CommonResult?generateTokenByHMAC()?{
????????try?{
????????????PayloadDto?payloadDto?=?jwtTokenService.getDefaultPayloadDto();
????????????String?token?=?jwtTokenService.generateTokenByHMAC(JSONUtil.toJsonStr(payloadDto),?SecureUtil.md5("test"));
????????????return?CommonResult.success(token);
????????}?catch?(JOSEException?e)?{
????????????e.printStackTrace();
????????}
????????return?CommonResult.failed();
????}
????@ApiOperation("使用對稱加密(HMAC)算法驗證token")
????@RequestMapping(value?=?"/hmac/verify",?method?=?RequestMethod.GET)
????@ResponseBody
????public?CommonResult?verifyTokenByHMAC(String?token)?{
????????try?{
????????????PayloadDto?payloadDto??=?jwtTokenService.verifyTokenByHMAC(token,?SecureUtil.md5("test"));
????????????return?CommonResult.success(payloadDto);
????????}?catch?(ParseException?|?JOSEException?e)?{
????????????e.printStackTrace();
????????}
????????return?CommonResult.failed();
????}
}
- 調用使用HMAC算法生成JWT令牌的接口進行測試;
- 調用使用HMAC算法解析JWT令牌的接口進行測試。
非對稱加密(RSA)
非對稱加密指的是使用公鑰和私鑰來進行加密解密操作。對于加密操作,公鑰負責加密,私鑰負責解密,對于簽名操作,私鑰負責簽名,公鑰負責驗證。非對稱加密在JWT中的使用顯然屬于簽名操作。
- 如果我們需要使用固定的公鑰和私鑰來進行簽名和驗證的話,我們需要生成一個證書文件,這里將使用Java自帶的keytool工具來生成jks證書文件,該工具在JDK的bin目錄下;
- 打開CMD命令界面,使用如下命令生成證書文件,設置別名為jwt,文件名為jwt.jks;
- 輸入密碼為123456,然后輸入各種信息之后就可以生成證書jwt.jks文件了;
- 將證書文件jwt.jks復制到項目的resource目錄下,然后需要從證書文件中讀取RSAKey,這里我們需要在pom.xml中添加一個Spring Security的RSA依賴;
<dependency>
????<groupId>org.springframework.securitygroupId>
????<artifactId>spring-security-rsaartifactId>
????<version>1.0.7.RELEASEversion>
dependency>
- 然后在JwtTokenServiceImpl類中添加方法,從類路徑下讀取證書文件并轉換為RSAKey對象;
?*?Created?by?macro?on?2020/6/22.
?*/
@Service
public?class?JwtTokenServiceImpl?implements?JwtTokenService?{
????@Override
????public?RSAKey?getDefaultRSAKey()?{
????????//從classpath下獲取RSA秘鑰對
????????KeyStoreKeyFactory?keyStoreKeyFactory?=?new?KeyStoreKeyFactory(new?ClassPathResource("jwt.jks"),?"123456".toCharArray());
????????KeyPair?keyPair?=?keyStoreKeyFactory.getKeyPair("jwt",?"123456".toCharArray());
????????//獲取RSA公鑰
????????RSAPublicKey?publicKey?=?(RSAPublicKey)?keyPair.getPublic();
????????//獲取RSA私鑰
????????RSAPrivateKey?privateKey?=?(RSAPrivateKey)?keyPair.getPrivate();
????????return?new?RSAKey.Builder(publicKey).privateKey(privateKey).build();
????}
}
- 我們可以在JwtTokenController中添加一個接口,用于獲取證書中的公鑰;
?*?JWT令牌管理Controller
?*?Created?by?macro?on?2020/6/22.
?*/
@Api(tags?=?"JwtTokenController",?description?=?"JWT令牌管理")
@Controller
@RequestMapping("/token")
public?class?JwtTokenController?{
????@Autowired
????private?JwtTokenService?jwtTokenService;
????
????@ApiOperation("獲取非對稱加密(RSA)算法公鑰")
????@RequestMapping(value?=?"/rsa/publicKey",?method?=?RequestMethod.GET)
????@ResponseBody
????public?Object?getRSAPublicKey()?{
????????RSAKey?key?=?jwtTokenService.getDefaultRSAKey();
????????return?new?JWKSet(key).toJSONObject();
????}
}
- 調用該接口,查看公鑰信息,公鑰是可以公開訪問的;
- 在JwtTokenServiceImpl中添加根據RSA算法生成和解析JWT令牌的方法,可以發現和上面的HMAC算法操作基本一致;
?*?Created?by?macro?on?2020/6/22.
?*/
@Service
public?class?JwtTokenServiceImpl?implements?JwtTokenService?{
????@Override
????public?String?generateTokenByRSA(String?payloadStr,?RSAKey?rsaKey)?throws?JOSEException?{
????????//創建JWS頭,設置簽名算法和類型
????????JWSHeader?jwsHeader?=?new?JWSHeader.Builder(JWSAlgorithm.RS256)
????????????????.type(JOSEObjectType.JWT)
????????????????.build();
????????//將負載信息封裝到Payload中
????????Payload?payload?=?new?Payload(payloadStr);
????????//創建JWS對象
????????JWSObject?jwsObject?=?new?JWSObject(jwsHeader,?payload);
????????//創建RSA簽名器
????????JWSSigner?jwsSigner?=?new?RSASSASigner(rsaKey,?true);
????????//簽名
????????jwsObject.sign(jwsSigner);
????????return?jwsObject.serialize();
????}
????@Override
????public?PayloadDto?verifyTokenByRSA(String?token,?RSAKey?rsaKey)?throws?ParseException,?JOSEException?{
????????//從token中解析JWS對象
????????JWSObject?jwsObject?=?JWSObject.parse(token);
????????RSAKey?publicRsaKey?=?rsaKey.toPublicJWK();
????????//使用RSA公鑰創建RSA驗證器
????????JWSVerifier?jwsVerifier?=?new?RSASSAVerifier(publicRsaKey);
????????if?(!jwsObject.verify(jwsVerifier))?{
????????????throw?new?JwtInvalidException("token簽名不合法!");
????????}
????????String?payload?=?jwsObject.getPayload().toString();
????????PayloadDto?payloadDto?=?JSONUtil.toBean(payload,?PayloadDto.class);
????????if?(payloadDto.getExp()?new?Date().getTime())?{
????????????throw?new?JwtExpiredException("token已過期!");
????????}
????????return?payloadDto;
????}
}
- 在JwtTokenController類,添加根據RSA算法生成和解析JWT令牌的接口,使用默認的RSA鑰匙對;
?*?JWT令牌管理Controller
?*?Created?by?macro?on?2020/6/22.
?*/
@Api(tags?=?"JwtTokenController",?description?=?"JWT令牌管理")
@Controller
@RequestMapping("/token")
public?class?JwtTokenController?{
????@Autowired
????private?JwtTokenService?jwtTokenService;
????@ApiOperation("使用非對稱加密(RSA)算法生成token")
????@RequestMapping(value?=?"/rsa/generate",?method?=?RequestMethod.GET)
????@ResponseBody
????public?CommonResult?generateTokenByRSA()?{
????????try?{
????????????PayloadDto?payloadDto?=?jwtTokenService.getDefaultPayloadDto();
????????????String?token?=?jwtTokenService.generateTokenByRSA(JSONUtil.toJsonStr(payloadDto),jwtTokenService.getDefaultRSAKey());
????????????return?CommonResult.success(token);
????????}?catch?(JOSEException?e)?{
????????????e.printStackTrace();
????????}
????????return?CommonResult.failed();
????}
????@ApiOperation("使用非對稱加密(RSA)算法驗證token")
????@RequestMapping(value?=?"/rsa/verify",?method?=?RequestMethod.GET)
????@ResponseBody
????public?CommonResult?verifyTokenByRSA(String?token)?{
????????try?{
????????????PayloadDto?payloadDto??=?jwtTokenService.verifyTokenByRSA(token,?jwtTokenService.getDefaultRSAKey());
????????????return?CommonResult.success(payloadDto);
????????}?catch?(ParseException?|?JOSEException?e)?{
????????????e.printStackTrace();
????????}
????????return?CommonResult.failed();
????}
}
- 調用使用RSA算法生成JWT令牌的接口進行測試;
- 調用使用RSA算法解析JWT令牌的接口進行測試。
參考資料
官方文檔:https://connect2id.com/products/nimbus-jose-jwt
項目源碼地址
https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-jwt
推薦閱讀
- 線上項目出BUG沒法調試?推薦這款阿里開源的診斷神器!
- Spring Boot 把 Maven 干掉了,正式擁抱 Gradle!
- 性能優越的輕量級日志收集工具,微軟、亞馬遜都在用!
- 15個Github使用技巧,你肯定有不知道的!
- 寫了100多篇原創文章,我常用的在線工具網站推薦給大家!
- 還在用Swagger生成接口文檔?我推薦你試試它.....
- 你居然還去服務器上撈日志,搭個日志收集系統難道不香么!
- 真慘!連各大編程語言都擺起地攤了,Java攤位真大!
- 一個不容錯過的Spring Cloud實戰項目!
- 我的Github開源項目,從0到20000 Star!
歡迎關注,點個在看
總結
以上是生活随笔為你收集整理的golang jwt设置过期_听说你的JWT库用起来特别扭,推荐这款贼好用的!的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 幻塔蓝色的花怎么打开
- 下一篇: 多重继承_Python 和 Java 基
