Spring Session - find by username

此指南介绍了如何使用 Spring Session 按用户名查找会话。

您可以在findbyusername application中找到已完成指南。

Assumptions

本指南假设你已使用内置 Redis 配置支持将 Spring Session 添加到你的应用程序中。该指南还假设你已将 Spring Security 应用到你的应用程序中。但是,该指南具有某种通用性,并且只需少量更改即可应用于任何技术,我们将在本指南的后面介绍这一点。

如果你需要了解如何将 Spring Session 添加到你的项目中,请参见 samples and guides 的列表。

About the Sample

我们的示例使用此功能来使可能遭到入侵的用户的会话失效。考虑以下场景:

  • 用户进入图书馆并向应用程序验证身份。

  • 用户回家后,发现自己忘记注销。

  • 用户可以根据位置、创建时间、上次访问时间等线索从图书馆登录并结束会话。

使用他们进行身份验证的任何设备让用户在图书馆使会话失效不是很好吗?此示例说明如何实现这一点。

Using FindByIndexNameSessionRepository

要根据用户名查找用户,你必须首先选择一个实现 link:../#api-findbyindexnamesessionrepository[FindByIndexNameSessionRepositorySessionRepository。我们的示例应用程序假设 Redis 支持已设置妥当,因此我们可以开始。

Mapping the User Name

如果开发人员指示 Spring Session 哪个用户与 Session 关联,则 FindByIndexNameSessionRepository 才能根据用户名查找会话。通过确保名为 FindByUsernameSessionRepository.PRINCIPAL_NAME_INDEX_NAME 的会话属性填充有用户名,你可以完成该操作。

总的来说,你可以立即在用户进行身份验证后使用以下代码:

/*
 * Copyright 2014-2022 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;

import java.util.Map;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;

/**
 * @author Rob Winch
 *
 */
@ExtendWith(MockitoExtension.class)
class FindByIndexNameSessionRepositoryTests {

	@Mock
	FindByIndexNameSessionRepository<Session> sessionRepository;

	@Mock
	Session session;

	@Test
	void setUsername() {
		// tag::set-username[]
		String username = "username";
		this.session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);
		// end::set-username[]
	}

	@Test
	void findByUsername() {
		// tag::findby-username[]
		String username = "username";
		Map<String, Session> sessionIdToSession = this.sessionRepository.findByPrincipalName(username);
		// end::findby-username[]
	}

}

Mapping the User Name with Spring Security

因为我们使用 Spring Security,所以会自动为我们编制用户名索引。这意味着我们无需执行任何步骤来确保对用户名进行编制索引。

Adding Additional Data to the Session

可以将其他信息(如 IP 地址、浏览器、位置和其他详情)关联到会话,这样可以更方便用户了解他们正在查看哪个会话。

为此,确定您要使用的会话属性以及您希望提供什么信息。然后,创建以会话属性添加的 Java bean。例如,我们的示例应用程序包括会话的位置和访问类型,如下表所示:

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

我们然后在每个 HTTP 请求中使用 SessionDetailsFilter 将该信息注入会话,如下例所示:

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

我们获取所需信息,然后将 SessionDetails 设置为 Session 中的一个属性。当我们按用户名检索 Session 时,我们可以使用会话访问我们的 SessionDetails,就像访问任何其他会话属性一样。

您可能会想,为什么 Spring 会话一开始没有提供 SessionDetails 功能。我们有两个原因。第一个原因是,应用程序自己实现这一点非常简单。第二个原因是在会话中填充的信息(以及该信息的更新频率)在很大程度上取决于应用程序。

Finding sessions for a specific user

现在我们可以找到某个特定用户的所有会话。以下示例展示了如何进行此操作:

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

在我们的示例中,我们找到了当前登录用户的会话。但是,您可以修改它,让管理员使用一个表单来指定要查找哪个用户。

findbyusername Sample Application

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

Running the findbyusername Sample Application

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

$ ./gradlew :spring-session-sample-boot-findbyusername:bootRun

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

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

Exploring the security Sample Application

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

  • Username user

  • Password password

然后点击 Login 按钮。现在您应该会看到一条消息,指出您已使用先前输入的用户登录。您还应该看到一个针对当前已登录用户的会话列表。

您可以通过进行以下操作模拟我们在 About the Sample 节中讨论的流程:

  • 打开一个新的隐身窗口,并导航至 [role="bare"] [role="bare"]http://localhost:8080/

  • 输入以下内容以进行登录:

    • Username user

    • Password password

  • End your original session.

  • 刷新原始窗口,查看自己是否已注销。