1. 程式人生 > 其它 >討論兩種Redis中Token的儲存方式

討論兩種Redis中Token的儲存方式

摘要:本文討論一個問題:儲存token時,token與對應使用者id誰來作為key? 問題起源問題起源於要給公司的後臺管理系統新增許可權管理,選用的是開源框架shiro,而原本系統上是採用token做了登入校驗的。

本文分享自華為雲社群《討論兩種Redis中Token的儲存方式》,作者:洛葉飄。

問題起源

問題起源於要給公司的後臺管理系統新增許可權管理,選用的是開源框架shiro,而原本系統上是採用token做了登入校驗的。

我所採用的shiro驗證方式是,每次介面請求,根據token來獲取使用者id,然後通過shiro中的登入驗證機制來進行許可權校驗。因此,“根據token獲取使用者id”就要求在儲存使用者token時,以token為鍵值key,以使用者ID為value值。

然而此時面臨一個問題是,系統原本的token儲存方式如下,我們稱之為第一種:使用者ID為key。

cache.set(TOKEN_PREFIX + userid, token);

這就需要我做出判斷,需不需要修改token的儲存方式為下面的形式:我們稱之為第二種:token為key。

cache.set(TOKEN_PREFIX + token, userid);

思考

第一個問題,兩種方式是否都能夠實現需求功能?

我們需要實現的功能包括:

  1. 登入驗證
  2. shiro中的許可權驗證

登入驗證

對於"使用者ID為key"的方式,需要前端傳遞使用者id+token兩個值,驗證登入狀態需要我們根據前端傳遞的使用者ID,獲取資料庫中儲存的token,與前端傳遞的token進行校驗,如果一致,則校驗通過,否則返回錯誤資訊,提示使用者需要重新登入等等。

對於“token為key”的方式,前端至少需要傳遞token一個值,根據前端傳遞的token,獲取資料庫中儲存的使用者ID,如果能獲取到,則校驗通過,否則提示使用者token已過期,需要使用者重新登入等等。

shiro中的許可權驗證

shiro中的許可權驗證,涉及到具體的實現機制,以token為key的方式,就以我們的真實實現為例:

// shiro登入程式碼:
Subject s = SecurityUtils.getSubject();
JWTToken jwtToken = new JWTToken(token);
subject.login(jwtToken);
// 實現AuthenticationToken的類:
import org.apache.shiro.authc.AuthenticationToken; public class JWTToken implements AuthenticationToken { private static final long serialVersionUID = 1L; // 金鑰 private String token; public JWTToken(String token) { this.token = token; } @Override public Object getPrincipal() { return token; } @Override public Object getCredentials() { return token; } } /** * 自定義的登入驗證類: */ public class ShiroDbRealm extends AuthorizingRealm{ /** * 重寫shiro的token */ @Override public boolean supports(AuthenticationToken token) { return token instanceof JWTToken; } /** * 角色,許可權認證 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //這裡可以連線資料庫根據使用者賬戶進行查詢使用者角色許可權等資訊 return simpleAuthorizationInfo; } /** * 自定義認證 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { String token = (String) auth.getCredentials(); // 解密獲得userid,用於和資料庫進行對比 // getUserId實際就是通過token,在資料庫中取對應的userid Integer userid = JwtUtils.getUserId(token); if (tuserid == null) { throw new AuthenticationException("token 校驗失敗"); } return new SimpleAuthenticationInfo(token, token, getName()); } }

如果採用userid為key的方式,不難實現,也修改其實現方式,

第二個問題,兩種方式哪一種傳輸的資料量更少?

第一種方式需要前端每次請求都傳遞token+userid;而第二種實際上可以只傳遞token,後臺根據token解密(或資料庫查詢)來獲取使用者資訊。

第三個問題,兩種方式哪種更安全?

兩種方式的安全應該是一樣的,核心是後臺通過資料庫儲存token與userid的對應資訊。

個人意見

個人比較細化第二種,以token為key的方式,首先,前端傳遞簡單,只需要傳遞token即可;二是後端通過這種方式,可以統一當前登入人的獲取方式,而不是每次在介面中獲取header中的使用者id。

 

點選關注,第一時間瞭解華為雲新鮮技術~