讨论两种redis中token的存储方式【五月03】-4008云顶国际网站

发表于 2022/05/13 15:04:45 2022/05/13
【摘要】 本文讨论一个问题:存储token时,token与对应用户id谁来作为key? 问题起源问题起源于要给公司的后台管理系统添加权限管理,选用的是开源框架shiro,而原本系统上是采用token做了登录校验的。我所采用的shiro验证方式是,每次接口请求,根据token来获取用户id,然后通过shiro中的登录验证机制来进行权限校验。因此,“根据token获取用户id”就要求在存储用户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。

【4008云顶国际集团的版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。