场景:
在一些不能使用session,或者session不能保持的情况,通常服务器端产生一个token字符串标识用户登录状态。当前端调用后端接口时,将此token作为参数加入到请求中,这样能够避免依赖浏览器与服务端会话状态。token身份验证可用于多域名间保持用户状态,后端负载均衡非ip hash策略等情况。
实现过程:
- pom中增加redis和session依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
复制代码
- 在登陆过程中将用户信息和其他需要的信息放入session
HttpSession httpSession = request.getSession();
httpSession.setAttribute("user", user);
复制代码
- 把sessionId返回给前端
String sessionId = httpSession.getId();
JSONObject result = new JSONObject();
result.put("sessionId", sessionId);
复制代码
这样的流程就是经常使用session的方式。
token(sessionId)使用过程(重点)
重点是从session中获取user的过程,在接收到前端请求时,常见获取user的实现代码:
User user = (User) httpSession.getAttribute("user");
复制代码
但是这样就没有token什么事了,并没有是使用token来做验证。如果要想使用token(sessionId)获取到user,第一个想法就是直接从使用redisTemplate的hash操作,根据key获取到里面的内容,查看一下redis存储session的key,如图:
这里获取还要注意序列化的问题,只有使用相同方式序列化key后才能获取到值。
这种方式想想就很复杂,难道没有简洁的方式获取到这些值吗,存进去的时候挺简单,拿出来时候不能这么麻烦吧。本着对spring强大的信心,寻找到了一个bean: RedisOperationsSessionRepository redisOperationsSessionRepository; 看到这个类的名字就很亲切,猜想一定它一定能够解决问题。通过自动注入,然后调用方法,得出以下代码:
Session session=redisOperationsSessionRepository.findById(sessionId);
if(session==null){
throw new ForbidException("请重新登录");
}
user=session.getAttribute("user");
if(user==null){
redisOperationsSessionRepository.deleteById(sessionId);
}
复制代码
注意这里的session是org.springframework.session.Session,而不是javax.servlet.http.HttpSession(常用的那个session),但是两者有着密切关系,通过适配器模式,将javax.servlet.http.HttpSession转为org.springframework.session.Session。
这样就能很方便的通过这个token(sessionId)获取到存储在redis的session的信息。
这里显然RedisOperationsSessionRepository是解决的关键点,至于是如何找到它,有两种方法:
- 第一种,看spring-session-data-redis和spring-session-core源码,找到关键点,这种方法估计会多花3个小时的时间;
- 第二种,最简单直接,而且在找到之后再看源码会更清晰,如果感兴趣的话,评论超过5人,我更新文档进行说明,嘎嘎,大神请飘过,或指教。
欢迎交流,不足之处请大家指正。
欢迎访问我的blog championjing.github.io/