Spring Session and Spring Security

本指南介绍如何将 Spring 会话与 Spring 安全性结合使用。它假定您已经将 Spring 安全性应用于您的应用程序了。

This guide describes how to use Spring Session along with Spring Security. It assumes you have already applied Spring Security to your application.

你可以从security sample application中找到已完成的指南。

You can find the completed guide in the security-sample.

Updating Dependencies

在使用 Spring 会话之前,您必须更新依赖。如果您使用 Maven,您必须添加以下依赖:

Before you use Spring Session, you must update your dependencies. If you use Maven, you must add the following dependencies:

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

	<dependency>
		<groupId>org.springframework.session</groupId>
		<artifactId>spring-session-data-redis</artifactId>
		<version>{spring-session-version}</version>
		<type>pom</type>
	</dependency>
	<dependency>
		<groupId>io.lettuce</groupId>
		<artifactId>lettuce-core</artifactId>
		<version>{lettuce-core-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 配置:

After adding the required dependencies, we can create our Spring configuration. The Spring configuration is responsible for creating a servlet filter that replaces the HttpSession implementation with an implementation backed by Spring Session. To do so, add the following Spring Configuration:

Unresolved include directive in modules/ROOT/pages/guides/java-security.adoc - include::example$spring-session-samples/spring-session-sample-javaconfig-security/src/main/java/sample/Config.java[]
1 The @EnableRedisHttpSession annotation creates a Spring bean with the name of springSessionRepositoryFilter that implements Filter. The filter is in charge of replacing the HttpSession implementation to be backed by Spring Session. In this instance Spring Session is backed by Redis.
2 We create a RedisConnectionFactory that connects Spring Session to the Redis Server. We configure the connection to connect to localhost on the default port (6379) For more information on configuring Spring Data Redis, see the {docs-url}/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[reference documentation].

Servlet Container Initialization

我们的 Spring Configuration 创建了一个名为 springSessionRepositoryFilter 的 Spring bean,它实现了 FilterspringSessionRepositoryFilter bean 负责使用由 Spring 会话支持的自定义实现替换 HttpSession

Our security-spring-configuration created a Spring bean named springSessionRepositoryFilter that implements Filter. The springSessionRepositoryFilter bean is responsible for replacing the HttpSession with a custom implementation that is backed by Spring Session.

为了让我们的 Filter`发挥作用,Spring 需要加载我们的 `Config 类。由于我们的应用程序已通过使用 SecurityInitializer 类加载了 Spring 配置,因此我们可将配置类添加到其中。以下示例说明了如何进行此操作:

In order for our Filter to do its magic, Spring needs to load our Config class. Since our application is already loading Spring configuration by using our SecurityInitializer class, we can add our configuration class to it. The following example shows how to do so:

src/main/java/sample/SecurityInitializer.java
Unresolved include directive in modules/ROOT/pages/guides/java-security.adoc - include::example$spring-session-samples/spring-session-sample-javaconfig-security/src/main/java/sample/SecurityInitializer.java[]

最后,我们需要确保 Servlet 容器(即 Tomcat)为每个请求使用我们的 springSessionRepositoryFilter。非常重要的是,Spring 会话的 springSessionRepositoryFilter 要在 Spring 安全性的 springSecurityFilterChain 之前调用。这确保了 Spring 安全性使用的 HttpSession 由 Spring 会话支持。幸运的是,Spring 会话提供了一个称为 AbstractHttpSessionApplicationInitializer 的实用类程序,使得此操作变得容易。以下示例说明了如何进行此操作:

Last, we need to ensure that our Servlet Container (that is, Tomcat) uses our springSessionRepositoryFilter for every request. It is extremely important that Spring Session’s springSessionRepositoryFilter is invoked before Spring Security’s springSecurityFilterChain. This ensures that the HttpSession that Spring Security uses is backed by Spring Session. Fortunately, Spring Session provides a utility class named AbstractHttpSessionApplicationInitializer that makes doing so easy. The following example shows how to do so:

src/main/java/sample/Initializer.java
Unresolved include directive in modules/ROOT/pages/guides/java-security.adoc - include::example$spring-session-samples/spring-session-sample-javaconfig-security/src/main/java/sample/Initializer.java[]

我们的类 (Initializer) 的名称并不重要,重要的是我们必须延伸`AbstractHttpSessionApplicationInitializer`。

The name of our class (Initializer) does not matter. What is important is that we extend AbstractHttpSessionApplicationInitializer.

通过扩展 AbstractHttpSessionApplicationInitializer,我们可以确保名为 springSessionRepositoryFilter 的 Spring Bean 在 Spring 安全性的 springSecurityFilterChain 之前为每个请求向我们的 Servlet 容器注册。

By extending AbstractHttpSessionApplicationInitializer, we ensure that the Spring bean named springSessionRepositoryFilter is registered with our Servlet Container for every request before Spring Security’s springSecurityFilterChain .

security Sample Application

本节介绍如何使用 security 示例应用程序。

This section describes how to work with the security sample application.

Running the security Sample Application

您可以获取 源代码 并调用以下命令运行示例:

You can run the sample by obtaining the source code and invoking the following command:

$ ./gradlew :spring-session-sample-javaconfig-security:tomcatRun

要让示例发挥作用,你必须在 localhost 上 install Redis 2.8+ 并使用默认端口 (6379) 运行它。或者,你可以更新 RedisConnectionFactory 以指向 Redis 服务器。另一个选项是使用 Docker 在 localhost 上运行 Redis。有关详细说明,请参见 Docker Redis repository

For the sample to work, you must install Redis 2.8+ on localhost and run it with the default port (6379). Alternatively, you can update the RedisConnectionFactory to point to a Redis server. Another option is to use Docker to run Redis on localhost. See Docker Redis repository for detailed instructions.

您现在应该能够访问 [role="bare"][role="bare"]http://localhost:8080/ 中的应用程序。

You should now be able to access the application at [role="bare"]http://localhost:8080/

Exploring the security Sample Application

现在,您可以使用该应用程序了。输入以下内容来登录:

Now you can use the application. Enter the following to log in:

  • Username user

  • Password password

然后,请点击 Login 按钮。您现在应该会看到一条消息,提示您已使用之前输入的用户登录了。此用户的详细信息存储在 Redis 中,而不是在 Tomcat 的 HttpSession 实现中。

Now click the Login button. You should now see a message indicating your are logged in with the user entered previously. The user’s information is stored in Redis rather than Tomcat’s HttpSession implementation.

How Does It Work?

我们不使用 Tomcat 的 HttpSession,而将值存储在 Redis 中。Spring 会话使用由 Redis 支持的实现替换 HttpSession。当 Spring 安全性的 SecurityContextPersistenceFilterSecurityContext 保存到 HttpSession 中时,其随后将存储在 Redis 中。

Instead of using Tomcat’s HttpSession, we persist the values in Redis. Spring Session replaces the HttpSession with an implementation that is backed by Redis. When Spring Security’s SecurityContextPersistenceFilter saves the SecurityContext to the HttpSession, it is then persisted into Redis.

当创建新的 HttpSession 时,Spring Session 在浏览器中创建一个名为 SESSION 的 cookie。该 cookie 包含会话 ID。您可以查看 cookie(使用 ChromeFirefox)。

When a new HttpSession is created, Spring Session creates a cookie named SESSION in your browser. That cookie contains the ID of your session. You can view the cookies (with Chrome or Firefox).

您可以使用 redis-cli 删除该会话。例如,在基于 Linux 的系统中,您可以键入以下命令:

You can remove the session using redis-cli. For example, on a Linux-based system you can type the following command:

	$ redis-cli keys '*' | xargs redis-cli del

Redis 文档包含有关 installing redis-cli 的说明。

The Redis documentation has instructions for installing redis-cli.

或者,您还可以删除显式键。将以下命令输入到您的终端中,并确保使用 SESSION cookie 的值替换 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e

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

$ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e

现在,您可以访问 [role="bare"][role="bare"]http://localhost:8080/ 中的应用程序并看到我们不再通过身份验证。

Now you can visit the application at [role="bare"]http://localhost:8080/ and see that we are no longer authenticated.