对于最新的稳定版本,请使用 Spring Session 3.3.1

对于最新的稳定版本,请使用 Spring Session 3.3.1

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

您可以在 findbyusername 应用程序中找到完整的指南。
您可以在 findbyusername 应用程序中找到完整的指南。

假设

本指南假设您已经使用内置的 Redis 配置支持将 Spring Session 添加到您的应用程序中。 本指南还假设您已经将 Spring Security 应用于您的应用程序。 但是,我们该指南在某种程度上是通用的,可以应用于任何技术,只需进行最小的更改,我们将在指南的后面讨论。

如果您需要了解如何将 Spring Session 添加到您的项目中,请参阅示例和指南列表
如果您需要了解如何将 Spring Session 添加到您的项目中,请参阅示例和指南列表

关于示例

我们的示例使用此功能使可能已泄露的用户会话失效。 请考虑以下方案:

  • 用户转到库并向应用程序进行身份验证。

  • 用户回到家后发现他们忘记注销了。

  • 用户可以使用位置、创建时间、上次访问时间等线索从库登录和结束会话。

如果我们可以让用户从他们进行身份验证的任何设备上使库中的会话无效,那不是很好吗? 此示例演示了如何实现此操作。

FindByIndexNameSessionRepository

若要按用户名查找用户,必须首先选择实现 FindByIndexNameSessionRepository 的用户。 我们的示例应用程序假设 Redis 支持已设置好,因此我们已准备就绪。SessionRepository

映射用户名

FindByIndexNameSessionRepository如果开发人员指示 Spring Session 与哪个用户关联,则只能通过用户名找到会话。 为此,您可以确保使用用户名填充具有该名称的会话属性。SessionFindByUsernameSessionRepository.PRINCIPAL_NAME_INDEX_NAME

通常,可以在用户进行身份验证后立即使用以下代码执行此操作:

String username = "username";
this.session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);

将用户名与 Spring Security 映射

由于我们使用 Spring Security,因此会自动为我们索引用户名。 这意味着我们不需要执行任何步骤来确保用户名被索引。

向会话添加其他数据

最好将其他信息(例如 IP 地址、浏览器、位置和其他详细信息)关联到会话。 这样做可以使用户更容易知道他们正在查看哪个会话。

为此,请确定要使用的会话属性以及要提供的信息。 然后创建一个 Java Bean,并将其添加为 session 属性。 例如,我们的示例应用程序包括会话的位置和访问类型,如以下列表所示:

public class SessionDetails implements Serializable {

	private String location;

	private String accessType;

	public String getLocation() {
		return this.location;
	}

	public void setLocation(String location) {
		this.location = location;
	}

	public String getAccessType() {
		return this.accessType;
	}

	public void setAccessType(String accessType) {
		this.accessType = accessType;
	}

	private static final long serialVersionUID = 8850489178248613501L;

}

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

@Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
		throws IOException, ServletException {
	chain.doFilter(request, response);

	HttpSession session = request.getSession(false);
	if (session != null) {
		String remoteAddr = getRemoteAddress(request);
		String geoLocation = getGeoLocation(remoteAddr);

		SessionDetails details = new SessionDetails();
		details.setAccessType(request.getHeader("User-Agent"));
		details.setLocation(remoteAddr + " " + geoLocation);

		session.setAttribute("SESSION_DETAILS", details);
	}
}

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

您可能想知道为什么 Spring Session 不提供开箱即用的功能。 我们有两个原因。 第一个原因是应用程序自己实现这一点非常简单。 第二个原因是会话中填充的信息(以及该信息的更新频率)高度依赖于应用程序。SessionDetails
您可能想知道为什么 Spring Session 不提供开箱即用的功能。 我们有两个原因。 第一个原因是应用程序自己实现这一点非常简单。 第二个原因是会话中填充的信息(以及该信息的更新频率)高度依赖于应用程序。SessionDetails

查找特定用户的会话

现在,我们可以找到特定用户的所有会话。 以下示例演示如何执行此操作:

@Autowired
FindByIndexNameSessionRepository<? extends Session> sessions;

@RequestMapping("/")
public String index(Principal principal, Model model) {
	Collection<? extends Session> usersSessions = this.sessions.findByPrincipalName(principal.getName()).values();
	model.addAttribute("sessions", usersSessions);
	return "index";
}

在我们的实例中,我们找到当前登录用户的所有会话。 但是,您可以修改此设置,以便管理员使用表单来指定要查找的用户。

findbyusername示例应用程序

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

运行示例应用程序findbyusername

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

$ ./gradlew :spring-session-sample-boot-findbyusername:bootRun
若要使示例正常工作,必须在 localhost 上安装 Redis 2.8+ 并使用默认端口 (6379) 运行它。 或者,您可以将指向 Redis 服务器更新。 另一种选择是使用 Docker 在 localhost 上运行 Redis。 有关详细说明,请参阅 Docker Redis 存储库RedisConnectionFactory

您现在应该能够在 localhost:8080/ 访问该应用程序

探索安全示例应用程序

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

  • 用户名 user

  • 密码 密码

现在点击 登录 按钮。 您现在应该会看到一条消息,指示您已使用之前输入的用户登录。 您还应该看到当前登录用户的活动会话列表。

可以通过执行以下操作来模拟我们在“关于示例”部分中讨论的流程:

  • 打开一个新的隐身窗口并导航到 localhost:8080/

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

    • 用户名 user

    • 密码 密码

  • 结束原始会话。

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

若要使示例正常工作,必须在 localhost 上安装 Redis 2.8+ 并使用默认端口 (6379) 运行它。 或者,您可以将指向 Redis 服务器更新。 另一种选择是使用 Docker 在 localhost 上运行 Redis。 有关详细说明,请参阅 Docker Redis 存储库RedisConnectionFactory