1. 程式人生 > 實用技巧 >分散式環境下Session共享問題解決和原理講解

分散式環境下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的增刪查改方法