Spring Session - REST

本指南介绍了如何在使用 REST 端点时使用 Spring Session 将 Redis 透明地利用为 Web 应用程序的 HttpSession 提供支持。

您可以在 rest sample application 中找到已完成的指南。

Updating Dependencies

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

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 配置:

Unresolved include directive in modules/ROOT/pages/guides/java-rest.adoc - include::example$spring-session-samples/spring-session-sample-javaconfig-rest/src/main/java/sample/HttpSessionConfig.java[]
1 @EnableRedisHttpSession`注释创建一个名为`springSessionRepositoryFilter`的 Spring bean,该 Bean 实现`Filter。此滤波器负责替换`HttpSession`实现,使其受到 Spring 会话的支持。在本例中,Spring 会话受到 Redis 支持。
2 创建一个 RedisConnectionFactory,将它连接到 Spring Session 和 Redis Server。我们配置连接以连接到默认端口(6379)上的 localhost。有关配置 Spring Data Redis 的更多信息,请参阅 {docs-url}/spring-data/data-redis/docs/{spring-data-redis-version}/reference/html/[参考文档]。
3 我们自定义 Spring 会话的 HttpSession 集成,以使用 HTTP 标头传达当前会话信息,而非 cookie。

Servlet Container Initialization

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

为了让我们的 Filter 发挥作用,Spring 需要加载我们的 Config 类。我们在 Spring MvcInitializer 中提供配置,如下面的示例所示:

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

最后,我们需要确保我们的 Servlet 容器(即 Tomcat)对每个请求使用我们的 springSessionRepositoryFilter。幸运的是,Spring 会话提供了一个名为 AbstractHttpSessionApplicationInitializer 的实用程序类,使此操作变得简单。为此,使用默认构造函数扩展该类,如下面的示例所示:

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

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

rest Sample Application

本部分介绍如何使用 rest 样本应用程序。

Running the rest Sample Application

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

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

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

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

Exploring the rest Sample Application

你现在可以尝试使用该应用。要执行此操作,请使用你喜爱的 REST 客户端请求 [role="bare"][role="bare"]http://localhost:8080/。

	$ curl -v http://localhost:8080/

请注意,系统会提示您进行基本认证。提供以下用户名和密码信息:

  • Username user

  • Password password

然后,运行以下命令:

$ curl -v http://localhost:8080/ -u user:password

在输出中,您应会看到以下内容:

HTTP/1.1 200 OK
...
X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3

{"username":"user"}

具体来说,您应该注意我们响应的以下内容:

  • HTTP 状态现在是 200。

  • 我们有一个名为 `X-Auth-Token`的标头,其中包含新的会话 ID。

  • 显示当前用户名。

我们现在可以使用 X-Auth-Token 再次提出请求而无需再次提供用户名和密码。例如,如下命令输出了用户名,与之前一样:

	$ curl -v http://localhost:8080/ -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"

唯一的区别是会话 ID 未在响应头中提供,因为我们正在重复使用现有的会话。

如果我们使会话失效,X-Auth-Token 会显示在响应中,并附带一个空值。例如,如下命令使我们的会话失效:

	$ curl -v http://localhost:8080/logout -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"

在输出中,您可以看到 X-Auth-Token 提供了一个空 String,表明上一个会话已失效:

HTTP/1.1 204 No Content
...
X-Auth-Token:

How Does It Work?

Spring Security 与 SecurityContextPersistenceFilter 中的标准 HttpSession 交互。

现在,Spring Security 正在持久保留 Redis 中的值,而非使用 Tomcat 的 HttpSession。Spring Session 在浏览器中创建了一个名为 X-Auth-Token 的 header。该 header 包含会话的 ID。

如果您愿意,您可以轻松地看到会话是在 Redis 中创建的。为此,通过使用如下命令创建会话:

$ curl -v http://localhost:8080/ -u user:password

在输出中,您应会看到以下内容:

HTTP/1.1 200 OK
...
X-Auth-Token: 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e

{"username":"user"}

现在,您可以通过使用 redis-cli 删除会话。例如,在基于 Linux 的系统上,您可以输入:

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

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

或者,您还可以删除显式密钥。为此,请将以下内容输入到您的终端中,确保将 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e 替换为 SESSION cookie 的值:

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

现在,我们可以使用 X-Auth-Token 对我们已删除的会话发出另一个请求,并观察到我们被提示进行身份验证。例如,如下命令返回一个 HTTP 401:

	$ curl -v http://localhost:8080/ -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3"