对于最新稳定版本,请使用 Spring Session 4.0.2spring-doc.cadn.net.cn

Spring Session 和 Spring Security 与 Hazelcast

此指南描述了在使用Hazelcast作为数据存储时,如何结合Spring Security和Spring Session的用法。 它假设您已经将Spring Security应用于您的应用程序。spring-doc.cadn.net.cn

您可以在Hazelcast Spring Security 样例应用中找到完整的指南。

更新依赖项

在使用Spring Session之前,您必须更新您的依赖项。 如果您使用Maven,请添加以下依赖项:spring-doc.cadn.net.cn

pom.xml
<dependencies>
	<!-- ... -->

	<dependency>
		<groupId>com.hazelcast</groupId>
		<artifactId>hazelcast</artifactId>
		<version>5.4.0</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-web</artifactId>
		<version>6.2.15</version>
	</dependency>
</dependencies>

Spring 配置

在添加了所需的依赖项后,我们可以创建我们的Spring配置。 Spring 配置负责创建一个servlet过滤器,该过滤器用基于Spring Session 的实现替换掉 HttpSession 实现。 要实现这一点,请添加以下Spring 配置:spring-doc.cadn.net.cn

@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 要支持按主体名称索引检索会话,需要注册一个合适的ValueExtractor。 Spring Session为此提供了PrincipalNameExtractor
3 为了高效地序列化MapSession对象,需要注册HazelcastSessionSerializer。如果不设置此配置,Hazelcast 将使用原生Java序列化来序列化会话。
4 我们创建一个HazelcastInstance来将Spring Session与Hazelcast连接起来。 默认情况下,应用程序启动并连接到嵌入式Hazelcast实例。 有关配置Hazelcast的更多信息,请参阅参考文档
如果希望使用HazelcastSessionSerializer,则需要在所有Hazelcast集群成员启动之前进行配置。 在Hazelcast集群中,所有成员都应使用相同的会话序列化方法。另外,如果使用了Hazelcast客户端/服务器架构,则成员和客户端都必须使用相同的序列化方法。可以通过ClientConfig注册序列化器,并使用与成员相同的SerializerConfiguration

Servlet 容器初始化

我们的Spring 配置创建了一个名为springSessionRepositoryFilter的 Spring bean,该bean实现了FilterspringSessionRepositoryFilter bean负责用一个由 Spring Session 支撑的自定义实现来替换HttpSessionspring-doc.cadn.net.cn

为了使我们的Filter发挥魔力,Spring 需要加载我们的SessionConfig类。 由于我们已经通过使用SecurityInitializer类来加载应用程序的 Spring 配置,因此我们可以将SessionConfig类添加到其中。 以下列表显示了如何实现这一点:spring-doc.cadn.net.cn

src/main/java/sample/SecurityInitializer.java
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的工具类,使得这一操作变得简单。 以下示例展示了如何实现这一点:spring-doc.cadn.net.cn

src/main/java/sample/Initializer.java
public class Initializer extends AbstractHttpSessionApplicationInitializer {

}
我们的类名(Initializer)无关紧要。重要的是我们继承了AbstractHttpSessionApplicationInitializer

通过扩展AbstractHttpSessionApplicationInitializer,我们确保名为springSessionRepositoryFilter的Spring bean在每次请求中都会被注册到我们的Servlet容器中,在Spring Security的springSecurityFilterChain之前。spring-doc.cadn.net.cn

Hazelcast Spring Security示例应用

此部分描述了如何与Hazelcast Spring Security示例应用程序进行交互。spring-doc.cadn.net.cn

运行示例应用程序

您可以运行示例程序,通过获取源代码并执行以下命令来实现:spring-doc.cadn.net.cn

$ ./gradlew :spring-session-sample-javaconfig-hazelcast:tomcatRun
默认情况下,Hazelcast会在应用程序中以嵌入模式运行。 但是,如果您想要连接到一个独立实例,可以通过遵循参考文档中的说明进行配置。

您应该能够通过以下地址访问应用:localhost:8080/spring-doc.cadn.net.cn

探索安全示例应用程序

现在您可以尝试使用应用程序。 要进行操作,请输入以下内容登录:spring-doc.cadn.net.cn

现在点击 登录 按钮。 你应该会看到一个消息,表明你已经使用之前输入的用户信息进行了登录。 用户的个人信息存储在 Hazelcast 而不是 Tomcat 的 HttpSession 实现中。spring-doc.cadn.net.cn

它是如何工作的?

我们不再使用Tomcat的HttpSession,而是将值持久化在Hazelcast中。spring-doc.cadn.net.cn

spring-doc.cadn.net.cn

Spring Session用一个由Hazelcast支持的实现替换了HttpSessionspring-doc.cadn.net.cn

当Spring Security的SecurityContextPersistenceFilterSecurityContext保存到HttpSession时,它会被持久化到Hazelcast中。spring-doc.cadn.net.cn

spring-doc.cadn.net.cn

当一个新创建的HttpSession被创建时,Spring Session会在您的浏览器中创建一个名为SESSION的cookie。该cookie包含了您会话的ID。 您可以使用ChromeFirefox查看这些cookies。spring-doc.cadn.net.cn

与数据存储交互

使用控制台

例如,在连接到您的Hazelcast节点后,可以通过管理中心控制台移除会话,请运行以下命令:spring-doc.cadn.net.cn

	default> ns spring:session:sessions
	spring:session:sessions> m.clear
The Hazelcast 文档有针对控制台的说明。控制台

Alternatively, you can also delete the explicit key. Enter the following into the console, being sure to replace 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e with the value of your SESSION cookie:spring-doc.cadn.net.cn

	spring:session:sessions> m.remove 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e

现在访问应用,在localhost:8080/,观察我们不再进行身份验证。spring-doc.cadn.net.cn

使用 REST API

如文档中描述的其他客户端部分所述,Hazelcast 节点提供了 REST APIspring-doc.cadn.net.cn

例如,您可以按照以下方式删除一个单独的密钥(请确保将7e8383a4-082c-4ffe-a4bc-c40fd3363c5e替换为您SESSION cookie的值):spring-doc.cadn.net.cn

	$ curl -v -X DELETE http://localhost:xxxxx/hazelcast/rest/maps/spring:session:sessions/7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
Hazelcast 节点的端口号在启动时会打印到控制台。请将 xxxxx 替换为端口号。

现在您已注销,无法再通过此会话进行身份验证。spring-doc.cadn.net.cn