写点什么

讨论两种 Redis 中 Token 的存储方式

  • 2022 年 5 月 16 日
  • 本文字数:1750 字

    阅读完需:约 6 分钟

本文分享自华为云社区《讨论两种Redis中Token的存储方式》,作者: 洛叶飘 。


本文讨论一个问题:

存储 token 时,token 与对应用户 id 谁来作为 key?

问题起源

问题起源于要给公司的后台管理系统添加权限管理,选用的是开源框架 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。


点击关注,第一时间了解华为云新鲜技术~​

发布于: 刚刚阅读数: 3
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
讨论两种Redis中Token的存储方式_Token_华为云开发者社区_InfoQ写作社区