Spring Session & Redis实现Session共享
前后端分离Session、单点登录实现 Session 共享简单方案,充当笔记
一、Session和Cookie
1.Session简介:
Session及会话,是web开发中得一种会话跟踪技术。
Session会话过程:当用户打开浏览器,从第一次请求开始,一直到最终关闭浏览器,就表示一次会话。
2.Cookie简介:
Cookie是由服务器生成,保存在客户端得一种消息载体。这个载体中存放这用户访问该站点得会话状态消息,只要Cookie没有被清空或者失效,那么保存中的会话会一直有效。
Cookie过程:用户在第一次请求时,有服务器生成Cookie,并将其封装到请求头中,以响应的形式发送给客户端。客户端将其保存,当客户端再次发送同样的请求后,请求中会携带Cookie发送服务端,服务器对会话进行跟踪。
3.Session和Cookie区别(简单说明)
Session保存在服务端,而Cookie保存在客户端。Session保存在服务端,关闭浏览器,就表示一次会话(session过期),而Cookie只要客户端没有被清空或者失效,那么保存中的会话会一直有效。(注意Cookie包含Session,都是以Cookie的形式存储)
例:
Session 客户端
Cookie
二、使用Session遇到的问题及场景
1.单个Tomcat时使用Session(单个Tomcat下Session不会出现大问题)
2.多个Tomcat时使用Session
看出问题了吗?这样的问题,TomcatB生成Session,访问TomcatA时,TomcatA并不知道TomcatB创建的Session,直接跨域问题或获取JsessionId后get导致返回null;
解决方案有很多:Session 黏连、Session 复制、Session 外部化存储(MySQL、MongoDB、Redis)。
快速入门Spring Session + Redis
前提:虽然Tomcat不一样,但是还是共用Redis的
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 实现对 Spring MVC 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 实现对 Spring Session 使用 Redis 作为数据源的自动化配置 -->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<!-- 实现对 Spring Data Redis 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<!-- 去掉对 Lettuce 的依赖,因为 Spring Boot 优先使用 Lettuce 作为 Redis 客户端 -->
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入 Jedis 的依赖,这样 Spring Boot 实现对 Jedis 的自动化配置 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
application.properties
#redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
拦截器:
/**
* @author lanys
* @Description:
* @date 3/6/2021 上午9:34
*/
@Configuration
public class WebSecurityConfig implements WebMvcConfigurer {
//自定义拦截
@Bean
public RedisSessionInterceptor redisSessionInterceptor(){
return new RedisSessionInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
//
registry.addInterceptor(redisSessionInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/user/login");
WebMvcConfigurer.super.addInterceptors(registry);
}
}
自定义拦截:
/**
* @author lanys
* @Description:
* @date 3/6/2021 上午9:36
*/
public class RedisSessionInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
String id = session.getId();
Integer loginUserId1 = (Integer) session.getAttribute("loginUserId");
if (session.getAttribute("loginUserId")!=null){
try{
String loginUserId= (String) redisTemplate.opsForValue().get("loginUserId:"+loginUserId1);
if (loginUserId!=null && loginUserId.equals(session.getId())){
return true;
}
}catch (Exception e){
e.printStackTrace();
}
}
response.getWriter().print( "用户未登录!");
return false;
}
}
LoginController:
/**
* @author lanys
* @Description:
* @date 3/6/2021 上午9:46
*/
@RestController
@RequestMapping(value = "/api/user")
public class LoginController {
@Autowired
private RedisTemplate redisTemplate;
@RequestMapping("/login")
public String login(HttpServletRequest request, Integer account, Integer password) throws Exception {
SysUser sysUser = new SysUser();
if ( sysUser.getAccount()==account && sysUser.getPassword()==password)
{
HttpSession session = request.getSession();
session.setAttribute("loginUserId", sysUser.getUserId());
redisTemplate.opsForValue().set("loginUserId:"+sysUser.getUserId(), session.getId());
return "登录成功";
}
else
{
throw new Exception("账户名或密码错误!");
}
}
@RequestMapping(value = "/getUserInfo")
public Object get(long userId) throws Exception {
SysUser sysUser = new SysUser();
if ( sysUser.getUserId()==userId)
{
return "查询成功!:"+sysUser.getUserId();
}
else
{
throw new Exception( "用户不存在!");
}
}
}
SysUser:
/**
* @author lanys
* @Description:
* @date 3/6/2021 上午9:47
*/
@Data
public class SysUser {
private int UserId=123456;
private int account=123;
private int password=123;
}
RedisSession:
/**
* @author lanys
* @Description: 开启自动化配置 Spring Session 使用 Redis 作为数据源
* maxInactiveIntervalInSeconds=30 30秒后过期
* @date 3/6/2021 上午11:07
*/
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 30)
@Configuration
public class RedisSession {
@Bean
public static ConfigureRedisAction configureRedisAction(){
return ConfigureRedisAction.NO_OP;
}
}
30秒后,过期了,查询不到数据(修改时间 RedisSession 类)
总结
该只是例子,主要充当思想,遇到了知道该怎么解决,有什么方案,文章结合网上其他博主的文章充当自己笔记。