HttpSession
整合
Spring Session 提供了與 HttpSession
透明整合的功能。這表示開發人員可以替換 HttpSession
的實作,改用由 Spring Session 支援的實作。
為何選擇 Spring Session 和 HttpSession
?
我們已經提過 Spring Session 提供了與 HttpSession
的透明整合,但我們可以從中獲得哪些好處呢?
-
叢集式 Session:Spring Session 使支援叢集式 Session變得輕而易舉,而無需受限於特定應用程式容器的解決方案。
-
RESTful API:Spring Session 讓在標頭中提供 Session ID 的方式,能夠與 RESTful API 協同運作
搭配 Redis 的 HttpSession
使用 Spring Session 與 HttpSession
的整合,需要先加入 Servlet 篩選器,才能讓任何使用 HttpSession
的功能運作。您可以選擇使用下列任一種方式來啟用此功能:
基於 Redis Java 的配置
本節說明如何使用基於 Java 的配置,以 Redis 作為 HttpSession
的後端儲存。
HttpSession 範例 提供了一個使用 Java 配置整合 Spring Session 和 HttpSession 的運作範例。您可以在接下來的幾個章節中閱讀整合的基本步驟,但我們建議您在整合自己的應用程式時,同時參考詳細的 HttpSession 指南。 |
Spring Java 配置
加入必要的依賴項後,我們可以建立 Spring 配置。Spring 配置負責建立一個 Servlet 篩選器,該篩選器會將 HttpSession
的實作替換為由 Spring Session 支援的實作。若要執行此操作,請加入以下 Spring 配置:
@Configuration(proxyBeanMethods = false)
@EnableRedisHttpSession (1)
public class Config {
@Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory(); (2)
}
}
1 | @EnableRedisHttpSession 註解會建立一個名為 springSessionRepositoryFilter 的 Spring Bean,它實作了 Filter 介面。此篩選器負責替換 HttpSession 的實作,使其由 Spring Session 支援。在此範例中,Spring Session 是由 Redis 支援。 |
2 | 我們建立一個 RedisConnectionFactory ,將 Spring Session 連接到 Redis 伺服器。我們將連線配置為連線到預設埠 (6379) 上的 localhost。如需配置 Spring Data Redis 的詳細資訊,請參閱參考文件。 |
Java Servlet 容器初始化
我們的 Spring 配置 建立了一個名為 springSessionRepositoryFilter
的 Spring Bean,它實作了 Filter
介面。springSessionRepositoryFilter
Bean 負責將 HttpSession
替換為由 Spring Session 支援的自訂實作。
為了讓我們的 Filter
發揮作用,Spring 需要載入我們的 Config
類別。最後,我們需要確保我們的 Servlet 容器(即 Tomcat)針對每個請求都使用我們的 springSessionRepositoryFilter
。幸運的是,Spring Session 提供了一個名為 AbstractHttpSessionApplicationInitializer
的實用程式類別,使這兩個步驟都變得容易。以下範例示範如何操作:
public class Initializer extends AbstractHttpSessionApplicationInitializer { (1)
public Initializer() {
super(Config.class); (2)
}
}
我們的類別名稱 (Initializer ) 並不重要。重要的是我們繼承了 AbstractHttpSessionApplicationInitializer 。 |
1 | 第一個步驟是繼承 AbstractHttpSessionApplicationInitializer 。這樣做可確保名為 springSessionRepositoryFilter 的 Spring Bean 已在我們的 Servlet 容器中註冊,以處理每個請求。 |
2 | AbstractHttpSessionApplicationInitializer 也提供了一種機制,以確保 Spring 載入我們的 Config 。 |
基於 Redis XML 的配置
本節說明如何使用基於 XML 的配置,以 Redis 作為 HttpSession
的後端儲存。
HttpSession XML 範例 提供了一個使用 XML 配置整合 Spring Session 和 HttpSession 的運作範例。您可以在接下來的幾個章節中閱讀整合的基本步驟,但我們建議您在整合自己的應用程式時,同時參考詳細的 HttpSession XML 指南。 |
Spring XML 配置
加入必要的依賴項後,我們可以建立 Spring 配置。Spring 配置負責建立一個 Servlet 篩選器,該篩選器會將 HttpSession
的實作替換為由 Spring Session 支援的實作。若要執行此操作,請加入以下 Spring 配置:
(1)
<context:annotation-config/>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"/>
(2)
<bean class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory"/>
1 | 我們使用 <context:annotation-config/> 和 RedisHttpSessionConfiguration 的組合,因為 Spring Session 尚未提供 XML 命名空間支援 (請參閱 gh-104)。這會建立一個名為 springSessionRepositoryFilter 的 Spring Bean,它實作了 Filter 介面。此篩選器負責替換 HttpSession 的實作,使其由 Spring Session 支援。在此範例中,Spring Session 是由 Redis 支援。 |
2 | 我們建立一個 RedisConnectionFactory ,將 Spring Session 連接到 Redis 伺服器。我們將連線配置為連線到預設埠 (6379) 上的 localhost。如需配置 Spring Data Redis 的詳細資訊,請參閱參考文件。 |
XML Servlet 容器初始化
我們的 Spring 配置 建立了一個名為 springSessionRepositoryFilter
的 Spring Bean,它實作了 Filter
介面。springSessionRepositoryFilter
Bean 負責將 HttpSession
替換為由 Spring Session 支援的自訂實作。
為了讓我們的 Filter
發揮作用,我們需要指示 Spring 載入我們的 session.xml
配置。我們可以透過以下配置來達成:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/session.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
ContextLoaderListener
會讀取 contextConfigLocation 並載入我們的 session.xml 配置。
最後,我們需要確保我們的 Servlet 容器(即 Tomcat)針對每個請求都使用我們的 springSessionRepositoryFilter
。以下程式碼片段為我們執行最後一個步驟:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
DelegatingFilterProxy
會查找名為 springSessionRepositoryFilter
的 Bean,並將其轉換為 Filter
。對於每個呼叫 DelegatingFilterProxy
的請求,都會呼叫 springSessionRepositoryFilter
。
搭配 Mongo 的 HttpSession
使用 Spring Session 與 HttpSession
的整合,需要先加入 Servlet 篩選器,才能讓任何使用 HttpSession
的功能運作。
本節說明如何使用基於 Java 的配置,以 Mongo 作為 HttpSession
的後端儲存。
HttpSession Mongo 範例 提供了一個使用 Java 配置整合 Spring Session 和 HttpSession 的運作範例。您可以在下方閱讀整合的基本步驟,但我們鼓勵您在整合自己的應用程式時,同時參考詳細的 HttpSession 指南。 |
您只需加入以下 Spring 配置即可:
@Configuration(proxyBeanMethods = false)
@EnableMongoHttpSession (1)
public class HttpSessionConfig {
@Bean
public JdkMongoSessionConverter jdkMongoSessionConverter() {
return new JdkMongoSessionConverter(Duration.ofMinutes(30)); (2)
}
}
1 | @EnableMongoHttpSession 註解會建立一個名為 springSessionRepositoryFilter 的 Spring Bean,它實作了 Filter 介面。此篩選器會將預設的 HttpSession 替換為以 MongoDB 為後端的 Bean。 |
2 | 將 Session 超時時間配置為 30 分鐘。 |
Session 序列化機制
為了能夠將 Session 物件持久化儲存在 MongoDB 中,我們需要提供序列化/反序列化機制。
預設情況下,Spring Session MongoDB 將使用 JdkMongoSessionConverter
。
但是,您可以透過在您的 Boot 應用程式中加入以下程式碼,切換到 JacksonMongoSessionConverter
:
@Bean
JacksonMongoSessionConverter mongoSessionConverter() {
return new JacksonMongoSessionConverter();
}
JacksonMongoSessionConverter
此機制使用 Jackson 將 Session 物件序列化為 JSON 以及從 JSON 反序列化。
透過建立以下 Bean:
@Bean
JacksonMongoSessionConverter mongoSessionConverter() {
return new JacksonMongoSessionConverter();
}
…您可以從預設的 (基於 JDK 的序列化) 切換為使用 Jackson。
如果您要與 Spring Security 整合 (透過將您的 Session 儲存在 MongoDB 中),此配置將註冊正確的白名單元件,以便 Spring Security 能夠正常運作。 |
如果您想要提供自訂 Jackson 模組,您可以透過顯式註冊模組來完成,如下所示:
Unresolved include directive in modules/ROOT/pages/http-session.adoc - include::example$spring-session-data-mongodb-dir/src/integration-test/java/org/springframework/session/data/mongo/integration/MongoRepositoryJacksonITest.java[]
JdkMongoSessionConverter
JdkMongoSessionConverter
使用標準 Java 序列化,將 Session 屬性對應以二進位形式持久化儲存到 MongoDB 中。但是,標準 Session 元素 (例如 ID、存取時間等) 仍然以純粹的 Mongo 物件形式寫入,並且可以讀取和查詢,無需額外操作。如果沒有定義明確的 AbstractMongoSessionConverter
Bean,則會使用 JdkMongoSessionConverter
。
還有一個接受 Serializer
和 Deserializer
物件的建構子,讓您可以傳遞自訂實作,當您想要使用非預設的類別載入器時,這尤其重要。
搭配 JDBC 的 HttpSession
您可以使用 Spring Session 與 HttpSession
的整合,方法是在任何使用 HttpSession
的功能之前加入 Servlet 篩選器。您可以選擇以下任一種方式來完成:
基於 JDBC Java 的配置
本節說明當您使用基於 Java 的配置時,如何使用關聯式資料庫作為 HttpSession
的後端儲存。
HttpSession JDBC 範例 提供了一個使用 Java 配置整合 Spring Session 和 HttpSession 的運作範例。您可以在接下來的幾個章節中閱讀整合的基本步驟,但我們鼓勵您在整合自己的應用程式時,同時參考詳細的 HttpSession JDBC 指南。 |
Spring Java 配置
加入必要的依賴項後,我們可以建立 Spring 配置。Spring 配置負責建立一個 Servlet 篩選器,該篩選器會將 HttpSession
的實作替換為由 Spring Session 支援的實作。若要執行此操作,請加入以下 Spring 配置:
@Configuration(proxyBeanMethods = false)
@EnableJdbcHttpSession (1)
public class Config {
@Bean
public EmbeddedDatabase dataSource() {
return new EmbeddedDatabaseBuilder() (2)
.setType(EmbeddedDatabaseType.H2)
.addScript("org/springframework/session/jdbc/schema-h2.sql")
.build();
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource); (3)
}
}
1 | @EnableJdbcHttpSession 註解會建立一個名為 springSessionRepositoryFilter 的 Spring Bean。該 Bean 實作了 Filter 介面。此篩選器負責替換 HttpSession 的實作,使其由 Spring Session 支援。在此範例中,Spring Session 是由關聯式資料庫支援。 |
2 | 我們建立一個 dataSource ,將 Spring Session 連接到 H2 資料庫的嵌入式實例。我們將 H2 資料庫配置為使用 Spring Session 中包含的 SQL 腳本來建立資料庫表格。 |
3 | 我們建立一個 transactionManager ,用於管理先前配置的 dataSource 的事務。 |
如需有關如何配置資料存取相關問題的更多資訊,請參閱Spring Framework 參考文件。
Java Servlet 容器初始化
我們的 Spring 配置 建立了一個名為 springSessionRepositoryFilter
的 Spring Bean,它實作了 Filter
介面。springSessionRepositoryFilter
Bean 負責將 HttpSession
替換為由 Spring Session 支援的自訂實作。
為了讓我們的 Filter
發揮作用,Spring 需要載入我們的 Config
類別。最後,我們需要確保我們的 Servlet 容器(即 Tomcat)針對每個請求都使用我們的 springSessionRepositoryFilter
。幸運的是,Spring Session 提供了一個名為 AbstractHttpSessionApplicationInitializer
的實用程式類別,使這兩個步驟都變得容易。以下範例示範如何操作:
public class Initializer extends AbstractHttpSessionApplicationInitializer { (1)
public Initializer() {
super(Config.class); (2)
}
}
我們的類別名稱 (Initializer) 並不重要。重要的是我們繼承了 AbstractHttpSessionApplicationInitializer 。 |
1 | 第一個步驟是繼承 AbstractHttpSessionApplicationInitializer 。這樣做可確保名為 springSessionRepositoryFilter 的 Spring Bean 已在我們的 Servlet 容器中註冊,以處理每個請求。 |
2 | AbstractHttpSessionApplicationInitializer 也提供了一種機制,以確保 Spring 載入我們的 Config 。 |
多個 DataSources
Spring Session 提供了 @SpringSessionDataSource
限定符,讓您可以明確宣告應將哪個 DataSource
Bean 注入到 JdbcIndexedSessionRepository
中。這在應用程式上下文中存在多個 DataSource
Bean 的情況下特別有用。
以下範例示範如何操作:
@EnableJdbcHttpSession
public class Config {
@Bean
@SpringSessionDataSource (1)
public EmbeddedDatabase firstDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2).addScript("org/springframework/session/jdbc/schema-h2.sql").build();
}
@Bean
public HikariDataSource secondDataSource() {
// ...
}
}
1 | 此限定符宣告 Spring Session 應使用 firstDataSource。 |
基於 JDBC XML 的配置
本節說明當您使用基於 XML 的配置時,如何使用關聯式資料庫作為 HttpSession
的後端儲存。
HttpSession JDBC XML 範例 提供了一個使用 XML 配置整合 Spring Session 和 HttpSession 的運作範例。您可以在接下來的幾個章節中閱讀整合的基本步驟,但我們鼓勵您在整合自己的應用程式時,同時參考詳細的 HttpSession JDBC XML 指南。 |
Spring XML 配置
加入必要的依賴項後,我們可以建立 Spring 配置。Spring 配置負責建立一個 Servlet 篩選器,該篩選器會將 HttpSession
的實作替換為由 Spring Session 支援的實作。以下清單顯示如何加入以下 Spring 配置:
(1)
<context:annotation-config/>
<bean class="org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessionConfiguration"/>
(2)
<jdbc:embedded-database id="dataSource" database-name="testdb" type="H2">
<jdbc:script location="classpath:org/springframework/session/jdbc/schema-h2.sql"/>
</jdbc:embedded-database>
(3)
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
1 | 我們使用 <context:annotation-config/> 和 JdbcHttpSessionConfiguration 的組合,因為 Spring Session 尚未提供 XML 命名空間支援 (請參閱 gh-104)。這會建立一個名為 springSessionRepositoryFilter 的 Spring Bean。該 Bean 實作了 Filter 介面。此篩選器負責替換 HttpSession 的實作,使其由 Spring Session 支援。在此範例中,Spring Session 是由關聯式資料庫支援。 |
2 | 我們建立一個 dataSource ,將 Spring Session 連接到 H2 資料庫的嵌入式實例。我們將 H2 資料庫配置為使用 Spring Session 中包含的 SQL 腳本來建立資料庫表格。 |
3 | 我們建立一個 transactionManager ,用於管理先前配置的 dataSource 的事務。 |
如需有關如何配置資料存取相關問題的更多資訊,請參閱Spring Framework 參考文件。
XML Servlet 容器初始化
我們的 Spring 配置 建立了一個名為 springSessionRepositoryFilter
的 Spring Bean,它實作了 Filter
介面。springSessionRepositoryFilter
Bean 負責將 HttpSession
替換為由 Spring Session 支援的自訂實作。
為了讓我們的 Filter
發揮作用,我們需要指示 Spring 載入我們的 session.xml
配置。我們透過以下配置來達成:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/session.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
ContextLoaderListener
會讀取 contextConfigLocation
並載入我們的 session.xml 配置。
最後,我們需要確保我們的 Servlet 容器(即 Tomcat)針對每個請求都使用我們的 springSessionRepositoryFilter
。以下程式碼片段為我們執行最後一個步驟:
<filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
DelegatingFilterProxy
會查找名為 springSessionRepositoryFilter
的 Bean,並將其轉換為 Filter
。對於每個呼叫 DelegatingFilterProxy
的請求,都會呼叫 springSessionRepositoryFilter
。
基於 JDBC Spring Boot 的配置
本節說明當您使用 Spring Boot 時,如何使用關聯式資料庫作為 HttpSession
的後端儲存。
HttpSession JDBC Spring Boot 範例 提供了一個使用 Spring Boot 整合 Spring Session 和 HttpSession 的運作範例。您可以在接下來的幾個章節中閱讀整合的基本步驟,但我們鼓勵您在整合自己的應用程式時,同時參考詳細的 HttpSession JDBC Spring Boot 指南。 |
Spring Boot 配置
加入必要的依賴項後,我們可以建立 Spring Boot 配置。由於 Spring Boot 具備一流的自動配置支援,因此只需加入依賴項,Spring Boot 就會為我們設定由關聯式資料庫支援的 Spring Session。
如果類別路徑中存在單一 Spring Session 模組,Spring Boot 會自動使用該儲存實作。如果您有多個實作,您必須選擇您希望用於儲存 Session 的 StoreType,如上所示。
在底層,Spring Boot 會套用相當於手動加入 @EnableJdbcHttpSession
註解的配置。這會建立一個名為 springSessionRepositoryFilter
的 Spring Bean。該 Bean 實作了 Filter
介面。此篩選器負責替換 HttpSession
的實作,使其由 Spring Session 支援。
您可以透過使用 application.properties
進一步自訂。以下清單顯示如何操作:
server.servlet.session.timeout= # Session timeout. If a duration suffix is not specified, seconds are used. spring.session.jdbc.initialize-schema=embedded # Database schema initialization mode. spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-@@platform@@.sql # Path to the SQL file to use to initialize the database schema. spring.session.jdbc.table-name=SPRING_SESSION # Name of the database table used to store sessions.
如需更多資訊,請參閱 Spring Boot 文件中關於Spring Session 的部分。
配置 DataSource
Spring Boot 會自動建立一個 DataSource
,將 Spring Session 連接到 H2 資料庫的嵌入式實例。在生產環境中,您需要更新您的配置以指向您的關聯式資料庫。例如,您可以將以下內容包含在您的 application.properties 中:
spring.datasource.url= # JDBC URL of the database. spring.datasource.username= # Login username of the database. spring.datasource.password= # Login password of the database.
如需更多資訊,請參閱 Spring Boot 文件中關於配置 DataSource 的部分。
Servlet 容器初始化
我們的 Spring Boot 配置 建立了一個名為 springSessionRepositoryFilter
的 Spring Bean,它實作了 Filter
介面。springSessionRepositoryFilter
Bean 負責將 HttpSession
替換為由 Spring Session 支援的自訂實作。
為了讓我們的 Filter
發揮作用,Spring 需要載入我們的 Config
類別。最後,我們需要確保我們的 Servlet 容器(即 Tomcat)針對每個請求都使用我們的 springSessionRepositoryFilter
。幸運的是,Spring Boot 為我們處理了這兩個步驟。
搭配 Hazelcast 的 HttpSession
使用 Spring Session 與 HttpSession
的整合,需要先加入 Servlet 篩選器,才能讓任何使用 HttpSession
的功能運作。
本節說明如何使用基於 Java 的配置,以 Hazelcast 作為 HttpSession
的後端儲存。
Hazelcast Spring 範例 提供了一個使用 Java 配置整合 Spring Session 和 HttpSession 的運作範例。您可以在接下來的幾個章節中閱讀整合的基本步驟,但我們鼓勵您在整合自己的應用程式時,同時參考詳細的 Hazelcast Spring 指南。 |
Spring 配置
加入必要的依賴項後,我們可以建立 Spring 配置。Spring 配置負責建立一個 Servlet 篩選器,該篩選器會將 HttpSession
的實作替換為由 Spring Session 支援的實作。若要執行此操作,請加入以下 Spring 配置:
@EnableHazelcastHttpSession (1)
@Configuration
public class HazelcastHttpSessionConfig {
@Bean
public HazelcastInstance hazelcastInstance() {
Config config = new Config();
AttributeConfig attributeConfig = new AttributeConfig()
.setName(HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
.setExtractorClassName(PrincipalNameExtractor.class.getName());
config.getMapConfig(HazelcastIndexedSessionRepository.DEFAULT_SESSION_MAP_NAME) (2)
.addAttributeConfig(attributeConfig)
.addIndexConfig(
new IndexConfig(IndexType.HASH, HazelcastIndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE));
SerializerConfig serializerConfig = new SerializerConfig();
serializerConfig.setImplementation(new HazelcastSessionSerializer()).setTypeClass(MapSession.class);
config.getSerializationConfig().addSerializerConfig(serializerConfig); (3)
return Hazelcast.newHazelcastInstance(config); (4)
}
}
1 | @EnableHazelcastHttpSession 註解會建立一個名為 springSessionRepositoryFilter 的 Spring Bean,它實作了 Filter 介面。此篩選器負責替換 HttpSession 的實作,使其由 Spring Session 支援。在此範例中,Spring Session 是由 Hazelcast 支援。 |
2 | 為了支援依據 Principal 名稱索引檢索 Session,需要註冊適當的 ValueExtractor 。Spring Session 為此目的提供了 PrincipalNameExtractor 。 |
3 | 為了有效率地序列化 MapSession 物件,需要註冊 HazelcastSessionSerializer 。如果未設定此項,Hazelcast 將使用原生 Java 序列化來序列化 Session。 |
4 | 我們建立一個 HazelcastInstance ,將 Spring Session 連接到 Hazelcast。預設情況下,應用程式會啟動並連線到 Hazelcast 的嵌入式實例。如需配置 Hazelcast 的更多資訊,請參閱參考文件。 |
如果首選 HazelcastSessionSerializer ,則需要在所有 Hazelcast 叢集成員啟動之前為其配置。在 Hazelcast 叢集中,所有成員都應對 Session 使用相同的序列化方法。此外,如果使用 Hazelcast Client/Server 拓撲,則成員和用戶端都必須使用相同的序列化方法。可以使用成員的相同 SerializerConfiguration ,透過 ClientConfig 註冊序列化器。 |
Servlet 容器初始化
我們的 Spring 配置 建立了一個名為 springSessionRepositoryFilter
的 Spring Bean,它實作了 Filter
介面。springSessionRepositoryFilter
Bean 負責將 HttpSession
替換為由 Spring Session 支援的自訂實作。
為了讓我們的 Filter
發揮作用,Spring 需要載入我們的 SessionConfig
類別。由於我們的應用程式已透過使用我們的 SecurityInitializer
類別來載入 Spring 配置,因此我們可以將我們的 SessionConfig
類別加入其中。以下清單顯示如何操作:
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
public SecurityInitializer() {
super(SecurityConfig.class, SessionConfig.class);
}
}
最後,我們需要確保我們的 Servlet 容器(即 Tomcat)針對每個請求都使用我們的 springSessionRepositoryFilter
。極其重要的是,Spring Session 的 springSessionRepositoryFilter
必須在 Spring Security 的 springSecurityFilterChain
之前調用。這樣做可確保 Spring Security 使用的 HttpSession
是由 Spring Session 支援。幸運的是,Spring Session 提供了一個名為 AbstractHttpSessionApplicationInitializer
的實用程式類別,使這樣做變得容易。以下範例示範如何操作:
public class Initializer extends AbstractHttpSessionApplicationInitializer {
}
我們的類別名稱 (Initializer ) 並不重要。重要的是我們繼承了 AbstractHttpSessionApplicationInitializer 。 |
透過繼承 AbstractHttpSessionApplicationInitializer
,我們確保名為 springSessionRepositoryFilter
的 Spring Bean 已在我們的 Servlet 容器中註冊,以處理每個請求,且在 Spring Security 的 springSecurityFilterChain
之前。
HttpSession
整合的運作方式
幸運的是,HttpSession
和 HttpServletRequest
(用於取得 HttpSession
的 API) 都是介面。這表示我們可以為每個 API 提供我們自己的實作。
本節說明 Spring Session 如何提供與 HttpSession 的透明整合。我們提供此內容是為了讓您了解底層發生的情況。此功能已整合,您不需自行實作此邏輯。 |
首先,我們建立一個自訂的 HttpServletRequest
,它會傳回 HttpSession
的自訂實作。它看起來像這樣:
public class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper {
public SessionRepositoryRequestWrapper(HttpServletRequest original) {
super(original);
}
public HttpSession getSession() {
return getSession(true);
}
public HttpSession getSession(boolean createNew) {
// create an HttpSession implementation from Spring Session
}
// ... other methods delegate to the original HttpServletRequest ...
}
任何傳回 HttpSession
的方法都會被覆寫。所有其他方法都由 HttpServletRequestWrapper
實作,並委派給原始的 HttpServletRequest
實作。
我們透過使用名為 SessionRepositoryFilter
的 Servlet Filter
來替換 HttpServletRequest
實作。以下虛擬碼顯示其運作方式:
public class SessionRepositoryFilter implements Filter {
public doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
HttpServletRequest httpRequest = (HttpServletRequest) request;
SessionRepositoryRequestWrapper customRequest =
new SessionRepositoryRequestWrapper(httpRequest);
chain.doFilter(customRequest, response, chain);
}
// ...
}
透過將自訂的 HttpServletRequest
實作傳遞到 FilterChain
中,我們確保在我們的 Filter
之後調用的任何內容都使用自訂的 HttpSession
實作。這突顯了為何 Spring Session 的 SessionRepositoryFilter
必須放置在任何與 HttpSession
互動的功能之前。
HttpSession
和 RESTful API
Spring Session 可以與 RESTful API 協同運作,方法是讓 Session 在標頭中提供。
REST 範例 提供了一個運作範例,說明如何在 REST 應用程式中使用 Spring Session 來支援使用標頭進行驗證。您可以遵循接下來幾個章節中描述的整合基本步驟,但我們鼓勵您在整合自己的應用程式時,同時參考詳細的 REST 指南。 |
Spring 配置
加入必要的依賴項後,我們可以建立 Spring 配置。Spring 配置負責建立一個 Servlet 篩選器,該篩選器會將 HttpSession
的實作替換為由 Spring Session 支援的實作。若要執行此操作,請加入以下 Spring 配置:
@Configuration
@EnableRedisHttpSession (1)
public class HttpSessionConfig {
@Bean
public LettuceConnectionFactory connectionFactory() {
return new LettuceConnectionFactory(); (2)
}
@Bean
public HttpSessionIdResolver httpSessionIdResolver() {
return HeaderHttpSessionIdResolver.xAuthToken(); (3)
}
}
1 | @EnableRedisHttpSession 註解會建立一個名為 springSessionRepositoryFilter 的 Spring Bean,它實作了 Filter 介面。此篩選器負責替換 HttpSession 的實作,使其由 Spring Session 支援。在此範例中,Spring Session 是由 Redis 支援。 |
2 | 我們建立一個 RedisConnectionFactory ,將 Spring Session 連接到 Redis 伺服器。我們將連線配置為連線到預設埠 (6379) 上的 localhost。如需配置 Spring Data Redis 的詳細資訊,請參閱參考文件。 |
3 | 我們客製化了 Spring Session 的 HttpSession 整合,使用 HTTP 標頭來傳達目前的 session 資訊,而不是 cookies。 |
Servlet 容器初始化
我們的 Spring 配置 建立了一個名為 springSessionRepositoryFilter
的 Spring Bean,它實作了 Filter
介面。springSessionRepositoryFilter
bean 負責將 HttpSession
取代為由 Spring Session 支援的客製化實作。
為了讓我們的 Filter
發揮作用,Spring 需要載入我們的 Config
類別。我們在 Spring 的 MvcInitializer
中提供配置,如下列範例所示
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SecurityConfig.class, HttpSessionConfig.class };
}
最後,我們需要確保我們的 Servlet 容器(也就是 Tomcat)為每個請求都使用我們的 springSessionRepositoryFilter
。幸運的是,Spring Session 提供了一個名為 AbstractHttpSessionApplicationInitializer
的工具類別,讓這件事變得容易。要做到這一點,請使用預設建構子擴展這個類別,如下列範例所示
public class Initializer extends AbstractHttpSessionApplicationInitializer {
}
我們的類別名稱 (Initializer ) 並不重要。重要的是我們繼承了 AbstractHttpSessionApplicationInitializer 。 |
使用 HttpSessionListener
Spring Session 透過宣告 SessionEventHttpSessionListenerAdapter
,將 SessionDestroyedEvent
和 SessionCreatedEvent
轉換為 HttpSessionEvent
,來支援 HttpSessionListener
。若要使用此支援,您需要
-
確保您的
SessionRepository
實作支援並配置為觸發SessionDestroyedEvent
和SessionCreatedEvent
。 -
將
SessionEventHttpSessionListenerAdapter
配置為 Spring bean。 -
將每個
HttpSessionListener
注入到SessionEventHttpSessionListenerAdapter
中
如果您使用 Redis 支援並將 enableIndexingAndEvents
設定為 true
,@EnableRedisHttpSession(enableIndexingAndEvents = true)
,您只需要將每個 HttpSessionListener
註冊為 bean 即可。例如,假設您想要支援 Spring Security 的並行控制,並且需要使用 HttpSessionEventPublisher
。在這種情況下,您可以將 HttpSessionEventPublisher
作為 bean 加入。在 Java 配置中,這可能看起來像這樣
@Configuration
@EnableRedisHttpSession
public class RedisHttpSessionConfig {
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
// ...
}
在 XML 配置中,這可能看起來像這樣
<bean class="org.springframework.security.web.session.HttpSessionEventPublisher"/>