Spring Session & Redis实现Session共享

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 客户端
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 类)
在这里插入图片描述

总结

该只是例子,主要充当思想,遇到了知道该怎么解决,有什么方案,文章结合网上其他博主的文章充当自己笔记。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值