Java生成及校驗(yàn)token的實(shí)踐
What is token?
token是令牌的意思,作用就像“通關(guān)令牌”一樣,持有token的請求會被“放行”,不持有token的請求可以被攔截(可以設(shè)置白名單使不被攔截,例如登陸請求)。
token是由服務(wù)端創(chuàng)建的一串字符串,登陸成功后發(fā)送給前端存儲在瀏覽器或本地中,以后每次發(fā)送請求都攜帶上。
1. 使用攔截器在請求發(fā)出前在請求頭中添加上 token。
2. 將 token 存儲在瀏覽器的 cookies 中,符合一些條件每次請求都會自動(dòng)帶上 token。
Token安全問題
- 在存儲的時(shí)候把token進(jìn)行對稱加密存儲,用時(shí)解開。
- 將請求URL、時(shí)間戳、token三者進(jìn)行合并加鹽簽名,服務(wù)端校驗(yàn)有效性。
- 這兩種辦法的出發(fā)點(diǎn)都是:竊取你存儲的數(shù)據(jù)較為容易,而反匯編你的程序hack你的加密解密和簽名算法是比較難的。然而其實(shí)說難也不難,所以終究是防君子不防小人的做法。話說加密存儲一個(gè)你要是被人扒開客戶端看也不會被噴明文存儲……
- 方法1它拿到存儲的密文解不開、方法2它不知道你的簽名算法和鹽,兩者可以結(jié)合食用。
- 但是如果token被人拷走,他自然也能植入到自己的手機(jī)里面,那到時(shí)候他的手機(jī)也可以以你的身份來用著,這你就瞎了。
- 于是可以提供一個(gè)讓用戶可以主動(dòng)expire一個(gè)過去的token類似的機(jī)制,在被盜的時(shí)候能遠(yuǎn)程止損。
- 在網(wǎng)絡(luò)層面上token明文傳輸?shù)脑挄浅5奈kU(xiǎn),所以建議一定要使用HTTPS,并且把token放在post body里
Why do we use token?
在前后端分離的web項(xiàng)目中,HTTP是無狀態(tài)協(xié)議,即使使用賬號密碼登陸,后端仍然無法分辨是誰發(fā)出的請求,要么后端不需要確認(rèn)請求者的身份,要么每次請求都攜帶身份信息供后端確認(rèn)。
顯然第一種方法對軟件的安全會造成極大的威脅,那么第二種方法就被改善成了token,token就是加密了的用戶身份信息。
token組成(Composition of token)
以jwt(java web token)為例,下圖介紹了詳細(xì)介紹了token的組成。
校驗(yàn)token(Verify token)
這里只說最基礎(chǔ)的校驗(yàn)。
token的加密一般是可逆的,后端接收到token中,還可以根據(jù)加密的算法再進(jìn)行解密,以獲取荷載中的用戶信息,因此荷載中不能放置密碼等信息。
第三部分由于加入了自己制定的秘鑰(秘鑰一般保存在后端代碼中),解密成功后會與前兩部分和保存的秘鑰進(jìn)行對比,對比成功了才算token驗(yàn)證通過。經(jīng)過這樣的雙重保障,這三部分每一部分被篡改都會被發(fā)現(xiàn)。
校驗(yàn)流程:
實(shí)操:
生成token(Generate token)
以生成jwt為例子,代碼如下:
<!-- 引入jwt --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.8.2</version> </dependency>
校驗(yàn)token(Verificationtoken)
@Slf4j public class JwtUtil { /** * 使用固定的解密秘鑰 */ private static final String SECRET = TOKEN_SECRET; /** * @version: V1.0 * @description: 生成token并驗(yàn)證token并解密token中的信息 * @param: userInfo 用戶手機(jī)號和用戶Id * @return: java.lang.String 返回token **/ public static String getToken(UserInfoEntity userInfo) { try{ //用秘鑰生成簽名 Algorithm algorithm = Algorithm.HMAC256(SECRET); //默認(rèn)頭部+載荷(手機(jī)號/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: 校驗(yàn)token是否正確 * @param: token * @param: userPhone * @return: UserInfoEntity token中的用戶信息(姓名/id) **/ public static UserInfoEntity verify(String token) { try { // 根據(jù)用戶信息userInfo生成JWT效驗(yàn)器 Algorithm algorithm = Algorithm.HMAC256(SECRET); JWTVerifier verifier = JWT.require(algorithm) .build(); // 效驗(yàn)TOKEN verifier.verify(token); log.info("token:{}校驗(yàn)成功成功",token); //返回token內(nèi)容 return getTokenInfo(token); } catch (Exception exception) { log.error("token校驗(yàn)異常:{}",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é):
在實(shí)際應(yīng)用中,還應(yīng)考慮安全性措施,如使用安全的隨機(jī)數(shù)生成器生成密鑰、定期更換密鑰、使用 HTTPS 等。
Token 的生成和校驗(yàn)機(jī)制為應(yīng)用程序提供了一種安全的身份驗(yàn)證和授權(quán)方式,可以用于用戶認(rèn)證、API 訪問控制等場景。正確實(shí)現(xiàn)和使用 Token 機(jī)制可以提高應(yīng)用程序的安全性和用戶體驗(yàn)。
到此這篇關(guān)于Java生成及校驗(yàn)token的實(shí)踐的文章就介紹到這了,更多相關(guān)Java生成及校驗(yàn)token內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android中Socket通信的實(shí)現(xiàn)方法概述
這篇文章主要介紹了Android中Socket通信的實(shí)現(xiàn)方法,很有實(shí)用價(jià)值,需要的朋友可以參考下2014-08-08Java之獲取客戶端真實(shí)IP地址的實(shí)現(xiàn)
在開發(fā)工作中,我們常常需要獲取客戶端的IP,本文主要介紹了Jav之獲取客戶端真實(shí)IP地址的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12Spring?MVC?請求映射路徑的配置實(shí)現(xiàn)前后端交互
在Spring?MVC中,請求映射路徑是指與特定的請求處理方法關(guān)聯(lián)的URL路徑,這篇文章主要介紹了Spring?MVC?請求映射路徑的配置,實(shí)現(xiàn)前后端交互,需要的朋友可以參考下2023-09-09Spring Boot訪問靜態(tài)資源css/js,你真的懂了嗎
在搭建springboot時(shí)經(jīng)常需要在html中訪問一些靜態(tài)資源,很多朋友不清楚如何在 Spring Boot中訪問靜態(tài)資源,本文給大家?guī)韮煞N解決方案,感興趣的朋友跟隨小編一起看看吧2021-05-05Mybatis分頁查詢主從表的實(shí)現(xiàn)示例
本文主要介紹了Mybatis分頁查詢主從表的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-09-09