Spring Session Redis 在不一樣服務間共享 Session 時的類共享方案

Spring Session Redis 是不安全的

當在多服務之間使用 Spring Session Redis 進行 Session 共享要很是當心,由於它很不安全,頗有可能致使整個服務實例不可用,沒法處理任何請求。其中比較危險的地方就是在進行序列化,反序列化的時候(這種類型的錯誤尤爲容易在沒有開發規範的團隊內發生,就是什麼樣的數據能夠往共享存儲裏面存,什麼樣的不能存。存的時候要以什麼樣的格式去存,這些都要有規定才比較安全。由於共享存儲是會影響到別人的不單單是爲了本身的服務用起來方便)。RedisSerializer 接口的實現都是在序列化和反序列化出錯的時候直接拋出異常從而致使整個請求錯誤。java

public interface RedisSerializer<T> {

	/**
	 * Serialize the given object to binary data.
	 * 
	 * @param t object to serialize
	 * @return the equivalent binary data
	 */
	byte[] serialize(T t) throws SerializationException;

	/**
	 * Deserialize an object from the given binary data.
	 * 
	 * @param bytes object binary representation
	 * @return the equivalent object instance
	 */
	T deserialize(byte[] bytes) throws SerializationException;
}

 

下面用一張圖來講明我遇到的問題。Spring Session 的誕生老實說並非爲了分佈式系統,而是爲集羣系統提供了一種 Session 解決方案。可是咱們把 Spring Session 用在了分佈式系統上用以解決 Session 共享的問題老實說自己就是有點難爲人家 Spring Session 了 。git

 

Spring Session 實現 Session 共享的大體原理

Spring Session 實現 Session 共享的大體原理以下圖所示 , 使用一個 Filter 來攔截全部請求,在攔截到請求以後對 HttpServletRequest 和 HttpServletResponse 進行包裝 (HttpServletRequestWrapper  , HttpServletResponseWrapper)。在包裝中對 session 進行控制 ,將 session 數據都存儲在第三方存儲當中。redis

 

Spring Session Redis 在不一樣服務間共享 Session 時的類共享方案

在瞭解了 Spring Session 的工做原理後再去考慮這個問題就有頭緒了 。仍是經過圖形的方式來作大概的說明。spring

 

學習 Spring Session 的 SessionRepositoryFilter 的實現方式 , 添加一個 Filter 順序在 SessionRepositoryFilter 以後 , 在攔截過程當中包裝 HttpServletRequest , 重寫 getSession(boolean create)  和 getSession() 方法, 自定義一個 SafetyHttpSessionWrapper 包裝 Session ,重寫 setAttribute(String name , Object value) 函數 , 在保存屬性成功後利用 redis 的發佈訂閱機制發送消息到 redis , 消息的內容爲所保存對象的 .class 文件數據。在消息訂閱端 , 接收到消息後利用 javassist 和 net.bytebuddy.dynamic.loading.ByteArrayClassLoader 將 .class 文件數據加載轉換成 Class 的實例對象,可是這個  Class 實例的範圍被限定在 ByteArrayClassLoader 中 , 而這個 ByteArrayClassLoader 是提供給 RedisSerializer 內部使用的 , 好比 JdkSerializationRedisSerializer , GenericJackson2JsonRedisSerializer 都須要使用到 ClassLoader 。這樣當 服務A 在存儲任何自定義的對象在 Session 中時, 訪問服務 B 也不會出現讀取 Session 反序列化 ClassNotFoundException 的錯誤了。安全

 

第一版代碼實現

以上思路的代碼實如今 WORKX 項目中,感興趣的同窗能夠參考 org.hepeng.workx.spring.session.redis.serializer 這個包下的代碼。從 org.hepeng.workx.spring.session.redis.serializer.SafetyRedisSerializerConfiguration 這個類入手看源碼。目前 RedisSerializer 組件只支持了 JdkSerializationRedisSerializer , GenericJackson2JsonRedisSerializer 以及它們的子類。session

相關文章
相關標籤/搜索