Spring Session and Spring Security with Hazelcast
本指南描述了使用 Hazelcast 作为数据存储时,如何将 Spring 会话与 Spring 安全性配合使用。假设您已向应用程序应用了 Spring 安全性。
你可以在Hazelcast Spring Security sample application中找到已完成的指南。 |
Updating Dependencies
在使用 Spring 会话之前,您必须更新依赖。如果您使用 Maven,您必须添加以下依赖:
<dependencies>
<!-- ... -->
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>{hazelcast-version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>{spring-core-version}</version>
</dependency>
</dependencies>
Spring Configuration
在添加所需的依赖项后,我们可以创建我们的 Spring 配置。Spring 配置负责创建一个 Servlet 过滤器,该过滤器将 HttpSession
实现替换为由 Spring Session 支持的实现。为此,请添加以下 Spring 配置:
/*
* Copyright 2014-2023 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 com.hazelcast.config.AttributeConfig;
import com.hazelcast.config.Config;
import com.hazelcast.config.IndexConfig;
import com.hazelcast.config.IndexType;
import com.hazelcast.config.SerializerConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.MapSession;
import org.springframework.session.hazelcast.HazelcastIndexedSessionRepository;
import org.springframework.session.hazelcast.HazelcastSessionSerializer;
import org.springframework.session.hazelcast.PrincipalNameExtractor;
import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession;
// tag::config[]
@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)
}
}
// end::config[]
1 | @EnableHazelcastHttpSession 注释会创建一个 Spring bean,其名称为 springSessionRepositoryFilter`并会实现 `Filter 。该筛选器负责替换 HttpSession 实现,以便由 Spring Session 支持。在这种情况中,Spring Session 由 Hazelcast 支持。 |
2 | 为了支持按负责人姓名索引检索会话,需要注册一个适当的 ValueExtractor 。Spring Session为此提供了 PrincipalNameExtractor 。 |
3 | 为了高效序列化 MapSession 对象,需要注册 HazelcastSessionSerializer 。如果没有设置该属性,Hazelcast 将使用本机 Java 序列化来序列化会话。 |
4 | 创建一个 HazelcastInstance ,将它连接到 Spring Session 的 Hazelcast。默认情况下,应用程序会启动并连接到一个嵌入式 Hazelcast 实例。有关配置 Hazelcast 的更多信息,请参阅 reference documentation。 |
如果选择`HazelcastSessionSerializer`,则必须在所有 Hazelcast 集群成员开始之前对所有 Hazelcast 集群成员进行配置。在 Hazelcast 集群中,所有成员都应使用用于会话的相同序列化方法。此外,如果使用 Hazelcast 客户端/服务器拓扑结构,则成员和客户端都必须使用相同序列化方法。可以使用`ClientConfig`注册序列化程序并使用与成员相同的`SerializerConfiguration`。 |
Servlet Container Initialization
我们的 Spring Configuration 创建了一个名为 springSessionRepositoryFilter
的 Spring bean,它实现 Filter
。 springSessionRepositoryFilter
bean 负责用由 Spring Session 支持的自定义实现替换 HttpSession
。
为了让我们的 Filter`发挥作用,Spring 需要加载我们的 `SessionConfig
类。由于我们的应用程序已经通过使用我们的 SecurityInitializer
类加载了 Spring 配置,我们可以将我们的 SessionConfig
添加到该类。以下清单显示了如何执行此操作:
Unresolved include directive in modules/ROOT/pages/guides/java-hazelcast.adoc - include::example$spring-session-samples/spring-session-sample-javaconfig-hazelcast/src/main/java/sample/SecurityInitializer.java[]
最后,我们需要确保我们的 Servlet 容器(即 Tomcat)对每个请求使用我们的 springSessionRepositoryFilter
。Spring 会话的 springSessionRepositoryFilter
在 Spring Security 的 springSecurityFilterChain
之前调用非常重要。这样做可以确保 Spring Security 使用的 HttpSession
由 Spring 会话支持。幸运的是,Spring 会话提供了一个名为 AbstractHttpSessionApplicationInitializer
的实用程序类,使此操作变得简单。以下示例显示了如何执行此操作:
Unresolved include directive in modules/ROOT/pages/guides/java-hazelcast.adoc - include::example$spring-session-samples/spring-session-sample-javaconfig-hazelcast/src/main/java/sample/Initializer.java[]
我们的类 ( |
通过扩展 AbstractHttpSessionApplicationInitializer
,我们确保为 Spring 安全的 springSecurityFilterChain
注册名为 springSessionRepositoryFilter
的 Spring Bean 以便在对每个请求进行之前。
Hazelcast Spring Security Sample Application
本节描述如何使用 Hazelcast Spring 安全性示例应用程序。
Running the Sample Application
您可以获取 源代码 并调用以下命令运行示例:
$ ./gradlew :spring-session-sample-javaconfig-hazelcast:tomcatRun
默认情况下,Hazelcast 以嵌入模式在你的应用程序中运行。但是,如果你希望连接到独立实例,则可以通过按照 reference documentation 中的说明进行配置。 |
您现在应该能够访问 [role="bare"][role="bare"]http://localhost:8080/ 中的应用程序。
Exploring the Security Sample Application
您现在可以尝试使用该应用程序。为此,请输入以下内容进行登录:
-
Username user
-
Password password
单击 Login 按钮。您现在应该看到一条消息,指示您已使用之前输入的用户登录。用户的信息存储在 Hazelcast 中,而不是 Tomcat HttpSession
实现中。
How Does It Work?
我们不会使用 Tomcat 的 HttpSession
,而是将这些值持久保存到 Hazelcast 中。Spring 会话将 HttpSession
替换为由 Hazelcast 中的 Map
支持的实现。当 Spring 安全性的 SecurityContextPersistenceFilter
将 SecurityContext
保存到 HttpSession
时,它就被持久保存到 Hazelcast 中。
Interacting with the Data Store
您可以使用 a Java client one of the other clients 或 management center 来移除会话。
Using the Console
例如,要连接到 Hazelcast 节点后使用管理中心控制台删除会话,请运行以下命令:
default> ns spring:session:sessions spring:session:sessions> m.clear
Hazelcast 文档包含有关 the console 的说明。 |
或者,您也可以删除显式密钥。在控制台输入以下内容,务必将 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
替换为 SESSION
cookie 的值:
spring:session:sessions> m.remove 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
现在,再次访问 [role="bare"][role="bare"]http://localhost:8080/ 中的应用程序,并观察不再对我们进行身份验证的情况。
Using the REST API
如文档中介绍其他客户端的部分所述,Hazelcast 节点提供一个 REST API。
例如,您可以删除单独的密钥,如下所示(务必将 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
替换为 SESSION cookie 的值):
$ curl -v -X DELETE http://localhost:xxxxx/hazelcast/rest/maps/spring:session:sessions/7e8383a4-082c-4ffe-a4bc-c40fd3363c5e
Hazelcast 节点的端口号会在启动时打印到控制台中。使用端口号替换`xxxxx`。 |
现在,您可以看到,您不再通过该会话进行验证。