跳到主要内容

Spring Session - 按用户名查找

QWen Max 中英对照 Find by Username Spring Session - find by username

本指南描述了如何使用 Spring Session 按用户名查找会话。

备注

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

Index

前提

本指南假设您已经通过使用内置的Redis配置支持将Spring Session添加到您的应用程序中。本指南还假设您已经将Spring Security应用于您的应用程序。然而,本指南具有一定的通用性,只需稍作修改即可应用于任何技术,我们将在指南的后面部分讨论这一点。

备注

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

关于示例

我们的示例使用此功能来使可能已被破坏的用户会话失效。请考虑以下场景:

  • 用户前往图书馆并登录应用程序。

  • 用户回到家后意识到忘记注销了。

  • 用户可以使用位置、创建时间、最后访问时间等线索登录并结束在图书馆的会话。

如果用户能够通过任何他们用来认证的设备使图书馆的会话失效,这不是很好吗?此示例演示了如何实现这一点。

使用 FindByIndexNameSessionRepository

要通过用户名查找用户,您必须首先选择一个实现 FindByIndexNameSessionRepositorySessionRepository。我们的示例应用程序假定已经设置好了 Redis 支持,因此我们已经可以开始了。

映射用户名

FindByIndexNameSessionRepository 只能在开发人员指示 Spring Session 与 Session 关联的用户名称时,通过用户名查找会话。你可以通过确保会话属性中名为 FindByUsernameSessionRepository.PRINCIPAL_NAME_INDEX_NAME 的值被设置为用户名来实现这一点。

一般来说,您可以在用户身份验证后立即使用以下代码来实现:

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

映射用户名称与 Spring Security

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

向会话添加其他数据

将其他信息(如 IP 地址、浏览器、位置等详细信息)关联到会话可能很有帮助。这样做可以让用户更容易知道他们在查看哪个会话。

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

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;

}
java

然后,我们在每次 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);
}
}
java

我们获取所需的信息,然后将 SessionDetails 设置为 Session 中的一个属性。当我们通过用户名检索 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";
}
java

在我们的实例中,我们查找当前登录用户的所有会话。然而,你可以修改这一点,让管理员使用表单来指定要查询的用户。

findbyusername 示例应用程序

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

运行 findbyusername 示例应用程序

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

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

为了让示例正常工作,您必须在本地主机上安装 Redis 2.8+ 并使用默认端口(6379)运行它。或者,您可以更新 RedisConnectionFactory 以指向一个 Redis 服务器。另一个选项是使用 Docker 在本地主机上运行 Redis。有关详细说明,请参阅 Docker Redis 仓库

你现在应该能够访问 localhost:8080/ 上的应用程序了。

探索 security 示例应用程序

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

  • 用户名 user

  • 密码 password

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

你可以通过以下步骤模拟我们在关于示例部分讨论的流程:

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

  • 输入以下内容以登录:

    • 用户名 user

    • 密码 password

  • 结束您的原始会话。

  • 刷新原始窗口,查看您已登出。