HttpSession Integration
Spring Session 与 HttpSession 提供透明集成。这意味着开发人员可以将 HttpSession 实现替换为由 Spring Session 支持的实现。
Why Spring Session and HttpSession?
我们已经提到 Spring Session 与 HttpSession 提供透明集成,但我们从中获得了哪些好处?
-
Clustered Sessions: Spring 会话轻松支持clustered sessions,而无需绑定到特定于应用程序容器的解决方案。
-
RESTful APIs: Spring 会话允许在标头中提供会话 ID 以配合RESTful APIs工作
HttpSession with Redis
在 HttpSession 中使用 Spring Session 是通过在所有使用 HttpSession 的内容之前添加 Servlet Filter 来实现的。您可以选择通过使用以下任一种方式来启用此功能:
Redis Java-based Configuration
本节介绍如何使用基于 Java 的配置通过 Redis 来支持 HttpSession。
|
HttpSession Sample 提供了一个关于如何通过 Java 配置整合 Spring Session 和 |
@11
Redis XML-based Configuration
本节介绍如何使用基于 XML 的配置通过 Redis 来支持 HttpSession。
|
HttpSession XML Sample 提供了一个关于如何通过 XML 配置整合 Spring Session 和 |
@12
HttpSession with Mongo
使用 `HttpSession`的 Spring Session 可通过在使用 `HttpSession`的任何内容之前添加一个 Servlet 过滤器来启用。
本部分介绍如何使用 Mongo 来基于 Java 配置支持 HttpSession。
|
HttpSession Mongo Sample 提供了一个使用 Java 配置集成 Spring Session 和 |
@13
Session serialization mechanisms
为了能够在 MongoDB 中保存会话对象,我们需要提供序列化/反序列化机制。
默认情况下,Spring Session MongoDB 将使用 JdkMongoSessionConverter。
然而,你可以通过简单的将以下代码添加到你的 Boot 应用来切换到 JacksonMongoSessionConverter:
@Bean
JacksonMongoSessionConverter mongoSessionConverter() {
return new JacksonMongoSessionConverter();
}
JacksonMongoSessionConverter
此机制使用 Jackson 将会话对象序列化为/从 JSON。
通过创建以下 bean:
@Bean
JacksonMongoSessionConverter mongoSessionConverter() {
return new JacksonMongoSessionConverter();
}
…您能够从默认的(基于 JDK 的序列化)切换到使用 Jackson。
如果您要与 Spring Security 集成(通过在 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 序列化以二进制形式将会话属性映射持久性存储在 MongoDB 中。然而,诸如 id、访问时间等标准会话元素仍作为普通的 Mongo 对象进行写入,并且可以在不需要额外工作的情况下进行读取和查询。如果未定义显式的 AbstractMongoSessionConverter Bean,将使用 JdkMongoSessionConverter。
还存在一个使用 Serializer 和 Deserializer 对象的构造函数,它允许你传递自定义实现,这在想要使用非默认类加载器时尤为重要。
HttpSession with JDBC
你可以通过在使用 `HttpSession`的任何内容之前添加一个 Servlet 过滤器来使用 `HttpSession`的 Spring Session。你可以使用以下任何一种方式:
JDBC Java-based Configuration
本部分介绍了在使用基于 Java 的配置时如何使用关系数据库来支持 HttpSession。
|
HttpSession JDBC Sample 提供了一个关于如何通过 Java 配置整合 Spring Session 和 |
@14
JDBC XML-based Configuration
本节介绍了在基于 XML 的配置中使用关系数据库作为 HttpSession 的方法。
|
HttpSession JDBC XML Sample 提供了一个关于如何通过 XML 配置整合 Spring Session 和 |
@15
JDBC Spring Boot-based Configuration
本节介绍了在使用 Spring Boot 时如何使用关系数据库作为 HttpSession 的后盾。
|
HttpSession JDBC Spring Boot Sample 提供了一个关于如何通过 Spring Boot 整合 Spring Session 和 |
@16
HttpSession with Hazelcast
使用 `HttpSession`的 Spring Session 可通过在使用 `HttpSession`的任何内容之前添加一个 Servlet 过滤器来启用。
本节介绍了如何使用基于 Java 的配置,使用 Hazelcast 来支持 HttpSession。
|
Hazelcast Spring Sample 提供了一个工作示例,演示如何通过使用 Java 配置整合 Spring Session 和 |
@17
How HttpSession Integration Works
幸运的是,HttpSession 和 HttpServletRequest(用于获取一个 HttpSession 的 API)都是接口。这意味着我们为每个 API 提供我们自己的实现。
|
本节介绍了 Spring Session 如何提供与 |
首先,我们创建一个自定义的 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 会话的 SessionRepositoryFilter 放在与 HttpSession 交互的任何内容之前非常重要的原因。
HttpSession and RESTful APIs
Spring 会话可以通过让会话在标题中提供来处理 RESTful API。
|
REST Sample 提供了一个工作示例,演示如何在 REST 应用程序中使用 Spring Session 以支持通过标头进行身份验证。在接下来的部分中,你可以按照所述的基本整合步骤进行操作,但是我们建议你在与自己的应用程序整合时使用详细的 REST 指南。 |
@18
Using HttpSessionListener
Spring 会话通过将 SessionDestroyedEvent 和 SessionCreatedEvent 转换为 HttpSessionEvent,并声明 SessionEventHttpSessionListenerAdapter 来支持 HttpSessionListener。要使用此支持,您需要:
-
确保您的`SessionRepository`实现支持并配置为触发`SessionDestroyedEvent`和`SessionCreatedEvent`。
-
将`SessionEventHttpSessionListenerAdapter`配置为 Spring Bean。
-
在
HttpSessionListener中注入每个SessionEventHttpSessionListenerAdapter
如果您使用 Redis 支持,将 enableIndexingAndEvents 设置为 true、@EnableRedisHttpSession(enableIndexingAndEvents = true),您所要做的就是将每个 HttpSessionListener 注册为一个 Bean。例如,假设您希望支持 Spring Security 的并发控制,并且需要使用 HttpSessionEventPublisher。在这种情况下,您可以将 HttpSessionEventPublisher 添加为一个 Bean。在 Java 配置中,这可能如下所示:
/*
* Copyright 2014-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package docs.http;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
// tag::config[]
@Configuration
@EnableRedisHttpSession
public class RedisHttpSessionConfig {
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
// ...
}
// end::config[]
在 XML 配置中,这可能如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util-4.1.xsd">
<!-- tag::config[] -->
<bean class="org.springframework.security.web.session.HttpSessionEventPublisher"/>
<!-- end::config[] -->
<context:annotation-config/>
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisIndexedHttpSessionConfiguration"/>
<bean class="docs.http.AbstractHttpSessionListenerTests"
factory-method="createMockRedisConnection"/>
<bean class="docs.http.AbstractHttpSessionListenerTests$SecuritySessionDestroyedListener"/>
</beans>