Java生成及校驗token的實踐
What is token?
token是令牌的意思,作用就像“通關(guān)令牌”一樣,持有token的請求會被“放行”,不持有token的請求可以被攔截(可以設(shè)置白名單使不被攔截,例如登陸請求)。
token是由服務(wù)端創(chuàng)建的一串字符串,登陸成功后發(fā)送給前端存儲在瀏覽器或本地中,以后每次發(fā)送請求都攜帶上。
1. 使用攔截器在請求發(fā)出前在請求頭中添加上 token。

2. 將 token 存儲在瀏覽器的 cookies 中,符合一些條件每次請求都會自動帶上 token。

Token安全問題
- 在存儲的時候把token進行對稱加密存儲,用時解開。
- 將請求URL、時間戳、token三者進行合并加鹽簽名,服務(wù)端校驗有效性。
- 這兩種辦法的出發(fā)點都是:竊取你存儲的數(shù)據(jù)較為容易,而反匯編你的程序hack你的加密解密和簽名算法是比較難的。然而其實說難也不難,所以終究是防君子不防小人的做法。話說加密存儲一個你要是被人扒開客戶端看也不會被噴明文存儲……
- 方法1它拿到存儲的密文解不開、方法2它不知道你的簽名算法和鹽,兩者可以結(jié)合食用。
- 但是如果token被人拷走,他自然也能植入到自己的手機里面,那到時候他的手機也可以以你的身份來用著,這你就瞎了。
- 于是可以提供一個讓用戶可以主動expire一個過去的token類似的機制,在被盜的時候能遠(yuǎn)程止損。
- 在網(wǎng)絡(luò)層面上token明文傳輸?shù)脑挄浅5奈kU,所以建議一定要使用HTTPS,并且把token放在post body里
Why do we use token?
在前后端分離的web項目中,HTTP是無狀態(tài)協(xié)議,即使使用賬號密碼登陸,后端仍然無法分辨是誰發(fā)出的請求,要么后端不需要確認(rèn)請求者的身份,要么每次請求都攜帶身份信息供后端確認(rèn)。
顯然第一種方法對軟件的安全會造成極大的威脅,那么第二種方法就被改善成了token,token就是加密了的用戶身份信息。
token組成(Composition of token)
以jwt(java web token)為例,下圖介紹了詳細(xì)介紹了token的組成。

校驗token(Verify token)
這里只說最基礎(chǔ)的校驗。
token的加密一般是可逆的,后端接收到token中,還可以根據(jù)加密的算法再進行解密,以獲取荷載中的用戶信息,因此荷載中不能放置密碼等信息。
第三部分由于加入了自己制定的秘鑰(秘鑰一般保存在后端代碼中),解密成功后會與前兩部分和保存的秘鑰進行對比,對比成功了才算token驗證通過。經(jīng)過這樣的雙重保障,這三部分每一部分被篡改都會被發(fā)現(xiàn)。
校驗流程:

實操:
生成token(Generate token)
以生成jwt為例子,代碼如下:
<!-- 引入jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.2</version>
</dependency>校驗token(Verificationtoken)
@Slf4j
public class JwtUtil {
/**
* 使用固定的解密秘鑰
*/
private static final String SECRET = TOKEN_SECRET;
/**
* @version: V1.0
* @description: 生成token并驗證token并解密token中的信息
* @param: userInfo 用戶手機號和用戶Id
* @return: java.lang.String 返回token
**/
public static String getToken(UserInfoEntity userInfo) {
try{
//用秘鑰生成簽名
Algorithm algorithm = Algorithm.HMAC256(SECRET);
//默認(rèn)頭部+載荷(手機號/id)+簽名=jwt
String jwtToken= JWT.create()
.withClaim("userPhone", userInfo.getUserPhone())
.withClaim("userId", userInfo.getUserId())
.sign(algorithm);
log.info("用戶{}的token生成成功:{}",userInfo.getUserId(),jwtToken);
return jwtToken;
}catch (Exception e){
log.error("用戶{}的token生成異常:{}",userInfo.getUserId(),e);
return null;
}
}
/**
* @version: V1.0
* @description: 校驗token是否正確
* @param: token
* @param: userPhone
* @return: UserInfoEntity token中的用戶信息(姓名/id)
**/
public static UserInfoEntity verify(String token) {
try {
// 根據(jù)用戶信息userInfo生成JWT效驗器
Algorithm algorithm = Algorithm.HMAC256(SECRET);
JWTVerifier verifier = JWT.require(algorithm)
.build();
// 效驗TOKEN
verifier.verify(token);
log.info("token:{}校驗成功成功",token);
//返回token內(nèi)容
return getTokenInfo(token);
} catch (Exception exception) {
log.error("token校驗異常:{}",exception);
return null;
}
}
/**
* @version: V1.0
* @Title: getUsername
* @description: 從Token中解密獲得Token中的用戶信息
* @param: token
* @return: UserInfoEntity token中的用戶信息(姓名/id)
**/
private static UserInfoEntity getTokenInfo(String token) {
try {
DecodedJWT jwt = JWT.decode(token);
UserInfoEntity userInfo=new UserInfoEntity();
userInfo.setUserPhone(jwt.getClaim("userPhone").asString());
userInfo.setUserId(jwt.getClaim("userId").asString());
log.info("用戶{}從token獲取用戶信息成功",userInfo.getUserId());
return userInfo;
} catch (JWTDecodeException e) {
log.error("從token:{}獲取用戶信息異常:{}",token,e);
return null;
}
}
}
總結(jié):
在實際應(yīng)用中,還應(yīng)考慮安全性措施,如使用安全的隨機數(shù)生成器生成密鑰、定期更換密鑰、使用 HTTPS 等。
Token 的生成和校驗機制為應(yīng)用程序提供了一種安全的身份驗證和授權(quán)方式,可以用于用戶認(rèn)證、API 訪問控制等場景。正確實現(xiàn)和使用 Token 機制可以提高應(yīng)用程序的安全性和用戶體驗。
到此這篇關(guān)于Java生成及校驗token的實踐的文章就介紹到這了,更多相關(guān)Java生成及校驗token內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中使用標(biāo)簽(label)來控制循環(huán)的執(zhí)行流程
java 和 label 兩個完全不相干的詞,今天我把他們連接在一起了,試想一個問題,雙循環(huán)在不使用 return 的情況下,如何停止外循環(huán)?所以本文給大家介紹了Java中使用標(biāo)簽(label)來控制循環(huán)的執(zhí)行流程,需要的朋友可以參考下2024-06-06
Spring?Boot中的JdbcClient與JdbcTemplate使用對比分析
這篇文章主要介紹了Spring Boot中的JdbcClient與JdbcTemplate使用對比分析,一起看看Spring Boot 中 JdbcClient 和 JdbcTemplate 之間的差異2024-01-01
詳解spring cloud分布式整合zipkin的鏈路跟蹤
這篇文章主要介紹了詳解spring cloud分布式整合zipkin的鏈路跟蹤,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07
SpringCloud Gateway使用redis實現(xiàn)動態(tài)路由的方法
這篇文章主要介紹了SpringCloud Gateway使用redis實現(xiàn)動態(tài)路由的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01
Mybatis Generator Plugin悲觀鎖實現(xiàn)示例
本文將從悲觀鎖為例,讓你快速了解如何實現(xiàn)Mybatis Generator Plugin。文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09
mybatis多層嵌套resultMap及返回自定義參數(shù)詳解
這篇文章主要介紹了mybatis多層嵌套resultMap及返回自定義參數(shù)詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
idea使用spring Initializr 快速搭建springboot項目遇到的坑
這篇文章主要介紹了idea使用spring Initializr 快速搭建springboot項目遇到的坑,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11

