分布式下session认证出现的问题与使用spring session解决

分布式下session认证存在的问题

session认证: 客户端在服务端登录认证后,服务端自己保存用户信息,并把session_id放到客户端的cookie中,下次客户端带着cookie访问服务端就可以直接访问

这种session认证在分布式下会存在问题

  1. 无法访问其他相同模块的集群服务器

    因为只在一个服务端上保存信息,其他相同的集群服务器没保存

  2. 无法访问其他模块的服务器

    因为其他模块的服务器上未保存信息,所以无法访问

解决方案

  1. session复制

    • 只需要改tomcat配置文件
    • 占服务器的带宽,内存,浪费资源
  2. 客户端存储session

    • 服务端不用存session
    • 不安全(被篡改),cookie容量有限
  3. hash一致性(浏览器从哪个IP访问了服务端,就一直用那个服务端处理该浏览器的请求)

    • nginx提供了根据IP绑定服务端的负载均衡算法,只改nginx配置文件即可
    • 无法解决问题2
  4. 使用中间件Redis统一存储session

    • 问题2访问其他模块服务端时,可以使用子域session共享解决
    • 多增加了网络调用,redis获取数据比内存慢
  5. 使用基于token的认证方式

使用Spring session

解决分布式下session认证问题

spring session可以采用中间件redis统一存储session方案解决这个问题,同时还解决了redis获取数据速度慢的问题

  1. 导入依赖

    
            <dependency>
                <groupId>org.springframework.sessiongroupId>
                <artifactId>spring-session-data-redisartifactId>
            dependency>
    
  2. 编写配置文件

    #配置存到redis
    spring.session.store-type=redis 
    #过期时间
    server.servlet.session.timeout=30m
    
  3. 添加注解开启功能

    @EnableRedisHttpSession
    

此时已经完成了将session存在redis中的功能,还未解决session子域问题

分布式下session认证出现的问题与使用spring session解决_第1张图片

解决session子域问题,实际上就是修改产生session时设置的Domain

配置解决session域问题和序列化问题

@Configuration
public class GulimallSessionConfig {


    /**
     * 解决session域问题
     *
     * @return
     */
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();

        //设置Domain
        cookieSerializer.setDomainName("gulimall.com");
        //设置session名
        cookieSerializer.setCookieName("GULISESSION");

        return cookieSerializer;
    }


    /**
     * 设置session存储redis序列化为json格式
     *
     * @return
     */
    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }
}

分布式下session认证出现的问题与使用spring session解决_第2张图片

Spring session原理

  1. @EnableRedisHttpSession导入@Import(RedisHttpSessionConfiguration.class)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-of1NcEsI-1626313635270)(项目整合认证服务.assets/分布式下session认证出现的问题与使用spring session解决_第3张图片
)]

  1. RedisHttpSessionConfiguration中向容器添加了SessionRepository的实现类RedisOperationsSessionRepository

    2.1 SessionRepository接口的方法提供了对session的增删改查操作,那它的实现类RedisOperationsSessionRepository可想而知就是redis对session的增删改查操作

  2. RedisHttpSessionConfiguration继承了父类SpringHttpSessionConfiguration

在这里插入图片描述

3.1 SpringHttpSessionConfiguration的init中实现了之前我们加入容器的CookieSerializer(有就用我们的,没有就用默认的)

分布式下session认证出现的问题与使用spring session解决_第4张图片

3.2 SpringHttpSessionConfiguration还向容器中添加了SessionRepositoryFilter,SessionRepositoryFilter最终实现Filter接口,每个请求必须经过filter

分布式下session认证出现的问题与使用spring session解决_第5张图片

3.3 SessionRepositoryFilter构造的时候,会将SessionRepository放进去(这里会放实现类RedisOperationsSessionRepository)

分布式下session认证出现的问题与使用spring session解决_第6张图片

3.4 SessionRepositoryFilter使用装饰模式,在doFilterInternal方法中将原生请求,响应封装为SessionRepositoryRequestWrapper,SessionRepositoryResponseWrapper

分布式下session认证出现的问题与使用spring session解决_第7张图片

3.5 SessionRepositoryRequestWrapper中重写了getSession,所以我们拿到session存东西,一定会经过请求链,被它们用redis根据情况执行增删改查操作 [获取session要使用原生请求获得(HttpSession session1 = request.getSession(); HttpServletRequest request)]

总结

  • @EnableRedisHttpSession导入@Import(RedisHttpSessionConfiguration.class)

  • RedisHttpSessionConfiguration中向容器添加了SessionRepository的实现类RedisOperationsSessionRepository

    • SessionRepository接口的方法提供了对session的增删改查操作,那它的实现类RedisOperationsSessionRepository可想而知就是redis对session的增删改查操作
  • RedisHttpSessionConfiguration继承了父类SpringHttpSessionConfiguration

    • SpringHttpSessionConfiguration的init中实现了之前我们加入容器的CookieSerializer(有就用我们的,没有就用默认的)

    • SpringHttpSessionConfiguration还向容器中添加了SessionRepositoryFilter,SessionRepositoryFilter最终实现Filter接口,每个请求必须经过filter

    • SessionRepositoryFilter构造的时候,会将SessionRepository放进去(这里会放实现类RedisOperationsSessionRepository)

    • SessionRepositoryFilter使用装饰模式,在doFilterInternal方法中将原生请求,响应封装为SessionRepositoryRequestWrapper,SessionRepositoryResponseWrapper

    • SessionRepositoryRequestWrapper中重写了getSession,所以我们拿到session存东西,一定会经过请求链,被它们用redis根据情况执行增删改查操作[获取session要使用原生请求获得(HttpSession session1 = request.getSession(); HttpServletRequest request)]

  • 核心组件

    • SessionRepository(实现类RedisOperationsSessionRepository)

      • 使用redis对session进行增删改查
    • SessionRepositoryFilter

      • 装饰模式封装请求,响应,重写getSession的实现,用SessionRepository来对session进行增删改查

你可能感兴趣的:(项目,java)