分布式环境下Session共享问题解决和原理讲解

1、分布式环境下Session共享问题:

2、几种解决方法

3、通过后端统一存储方法在实际项目中问题的体现:

当session的作用域只限于auth.gulimall.com时,在auth.gulimall.com下登录账号所返回包含用户信息的session无法共享给gulimall.com

当我们把作用域放大更改为.gulimall.com时,auth.gulimall.com下登录账号所返回包含用户信息的session就能共享给gulimall.com

 

 至此解决session共享跨域问题的核心关键为放大session的作用域范围。

4、利用SpringSession作用域问题

①导入必要的包

        <!--springsession解决session共享问题-->
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>

②在需要进行session共享的微服务的配置文件中添加指定session存取至redis

spring.session.store-type=redis

③在需要进行session共享的微服务主启动类上开启reids的session的存取功能

@EnableRedisHttpSession//整合redis作为session存取
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class GulimallAuthServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(GulimallAuthServerApplication.class, args);
    }

}




@EnableRedisHttpSession//整合redis作为session存取
@EnableCaching
@EnableFeignClients(basePackages = "com.atguigu.gulimall.product.feign")
@EnableDiscoveryClient
@MapperScan(basePackages = "com.atguigu.gulimall.product.dao")
@SpringBootApplication
public class GulimallProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(GulimallProductApplication.class, args);
    }

}

④让session在不同域名下进行共享并对session进行序列化并以json格式的方式储存

官方文档:

 实际代码:

@Configuration
public class GulimallSessionConfig {
    //解决session跨域问题
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer cookieSerializer= new DefaultCookieSerializer();
        //将session作用域放大到*.gulimall.com
        cookieSerializer.setDomainName("gulimall.com");
        cookieSerializer.setCookieName("GULISESSION");
/*        serializer.setCookieName("JSESSIONID");
        serializer.setCookiePath("/");
        serializer.setDomainNamePattern("^.+?\.(\w+\.[a-z]+)$");*/
        return cookieSerializer;
    }

    //Session序列化后转为json格式
    @Bean
    public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        return new GenericJackson2JsonRedisSerializer();
    }
}

5、结果:

当我在auth.gulimall.com域名下的登录服务下将用户的账户信息传入session时:

if (oauthlogin.getCode()==0){
     MemberResVo data = oauthlogin.getData("data", new TypeReference<MemberResVo>() {});
     //TODO:1、session只作用当前域,无法跨域访问
     //TODO:2、希望能使用JSON序列化对象

     session.setAttribute("loginUser",data);
     return "redirect:http://gulimall.com";
}

此处使用MemberResVo实体类,所以要对其进行序列化:

@ToString
@Data
public class MemberResVo implements Serializable {
    private Long id;
    /**
     * 会员等级id
     */
    private Long levelId;
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    
   //private .....
   //private .....
}

至此我们可以将session返回给gulimall.com取得值并进行显示:

<a href="http://auth.gulimall.com/login.html">你好,[[${session.loginUser!=null?(session.loginUser.nickname!=null?session.loginUser.nickname:session.loginUser.socialUid):'请登录'}]]</a>

6、@EnableRedisHttpSession原理

@EnableRedisHttpSession导入RedisHttpSessionConfiguration.class
1、RedisHttpSessionConfiguration在容器中添加了RedisIndexedSessionRepository组件:redis操作session,对数据进行持久化处理

2、被RedisHttpSessionConfiguration继承的SpringHttpSessionConfiguration中添加了SessionRepositoryFilter(session过滤器)
2.1、SessionRepositoryFilter创建时自动获取到SessionRepository;
2.2、SessionRepositoryFilter的doFilterInternal方法把原生的request和response被包装成wrappedRequest和wrappedResponse,以后获取session将不再通过原生的request.session()方法而是通过wrappedRequest.getsession(),wrappedRequest.getsession()方法中重写了request.session(),wrappedRequest.getsession()的session是从SessionRepository获取得到的,做到从redis获取session

核心代码:

所以,我们可以通过自定义SessionRepository接口更改对session的增删查改方法

原文地址:https://www.cnblogs.com/linchenguang/p/13517076.html