最近做基於BFF架構的分佈式移動端API接口的系統設計。工作過程中發現有些工程師對JWT安全驗證的認識存在一些偏差,重複講解實在太麻煩了,在這裏把關於JWT常見的一些疑問統一回答下吧。
- 什麼是JWT?
JSON Web Token (JWT)是一種基於 token 的認證方案。
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
簡單的說,JWT就是一種Token的編碼算法,服務器端負責根據一個密碼和算法生成Token,然後發給客戶端,客戶端只負責後面每次請求都在HTTP header裏面帶上這個Token,服務器負責驗證這個Token是不是合法的,有沒有過期等,並可以解析出subject和claim裏面的數據。
注意JWT裏面的數據是BASE64編碼的,沒有加密,因此不要放如敏感數據。
可以通過https://jwt.io/這個網站對JWT Token進行解析。
一個JWT token 看起來是這樣的:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEzODY4OTkxMzEsImlzcyI6ImppcmE6MTU0ODk1OTUiLCJxc2giOiI4MDYzZmY0Y2ExZTQxZGY3YmM5MGM4YWI2ZDBmNjIwN2Q0OTFjZjZkYWQ3YzY2ZWE3OTdiNDYxNGI3MTkyMmU5IiwiaWF0IjoxMzg2ODk4OTUxfQ.uKqU9dTB6gKwG6jQCuXYAiMNdfNRw98Hw_IWuA5MaMo
可以簡化爲下面這樣的結構:
base64url_encode(Header) + '.' + base64url_encode(Claims) + '.' + base64url_encode(Signature)
- 爲什麼用JWT?
JWT只通過算法實現對Token合法性的驗證,不依賴數據庫,Memcached的等存儲系統,因此可以做到跨服務器驗證,只要密鑰和算法相同,不同服務器程序生成的Token可以互相驗證。
-
JWT Token需要持久化在Memcached中嗎?
不應該這樣做,這樣就背離了JWT通過算法驗證的初心。 -
在退出登錄時怎樣實現JWT Token失效呢?
退出登錄, 只要客戶端端把Token丟棄就可以了,服務器端不需要廢棄Token。 -
怎樣保持客戶端長時間保持登錄狀態?
服務器端提供刷新Token的接口, 客戶端負責按一定的邏輯刷新服務器Token。
- 服務器端是否應該從JWT中取出userid用於業務查詢?
REST API是無狀態的,意味着服務器端每次請求都是獨立的,即不依賴以前請求的結果,因此也不應該依賴JWT token做業務查詢, 應該在請求報文中單獨加個userid 字段。
爲了做用戶水平越權的檢查,可以在業務層判斷傳入的userid和從JWT token中解析出的userid是否一致, 有些業務可能會允許查不同用戶的數據。
- JWT 在Java項目中如何實現?
生成Token
String token = Jwts.builder().setSubject(userId)
.setExpiration(new Date(System.currentTimeMillis() + Constant.TOKEN_EXP_TIME))
.claim("roles", Constant.USER_TYPE_EMP).setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256, Constant.JWT_SECRET).compact();
loginResponse.setToken(token);
驗證JWT Token
final String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
log.debug("no Authorization ", e);
return;
} else {
try {
final String token = authHeader.substring(7); // The part after "Bearer "
log.debug("token " + token);
final Claims claims = Jwts.parser().setSigningKey(Constant.JWT_SECRET)
.parseClaimsJws(token).getBody();
log.debug(claims.toString());
} catch (Exception e) { //包含超時,簽名錯誤等異常
log.debug("JWT Exception", e);
return;
}
}
注意客戶端發送的Authorization HTTP HEADER格式是 "Bearer YOUR_JWT_TOKEN",這是OAuth的規範規定的。
作者:offbye西濤
鏈接:https://www.jianshu.com/p/b952c08aed09
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。