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

完成的指南可以在findbyusername应用程序中找到

1.假设

本指南假设您已使用内置的Redis配置支持向应用程序添加了Spring Session。该指南还假设您已将Spring Security应用于您的应用程序。但是,我们的指南将具有一定的通用性,可以应用于我们将讨论的最小变化的任何技术。

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

2.关于样品

我们的示例使用此功能使可能已被入侵的用户会话无效。请考虑以下情形:

  • 用户进入库并对应用程序进行身份验证

  • 用户回家后意识到他们忘了退出

  • 用户可以使用位置,创建时间,上次访问时间等线索登录并终止库中的会话。

如果我们允许用户从他们进行身份验证的任何设备中使库中的会话无效,那不是很好吗?此示例演示了如何实现这一点。

3. FindByIndexNameSessionRepository

要通过用户名查找用户,必须先选择实现FindByIndexNameSessionRepositorySessionRepository 我们的示例应用程序假设已经设置了Redis支持,因此我们准备好了。

4.映射用户名

如果开发人员指示Spring Session哪个用户与Session相关联,则FindByIndexNameSessionRepository只能通过用户名找到会话。这是通过确保使用用户名填充名称为FindByUsernameSessionRepository.PRINCIPAL_NAME_INDEX_NAME的会话属性来完成的。

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

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

5.使用Spring Security映射用户名

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

6.向会话添加其他数据

将附加信息(即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;
}

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

@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);
	}
}

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

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

7.为特定用户查找会话

我们现在可以找到特定用户的所有会话。

@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";
}

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

8. findbyusername示例应用程序

8.1.运行findbyusername示例应用程序

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

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

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

您现在应该可以在http:// localhost:8080 /访问该应用程序

8.2.探索安全性示例应用程序

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

  • 用户名 用户

  • 密码 密码

现在单击“ 登录”按钮。您现在应该看到一条消息,表明您已使用先前输入的用户登录。您还应该看到当前登录用户的活动会话列表。

让我们模拟我们在“ 关于样本”部分中讨论的流程

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

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

    • 用户名 用户

    • 密码 密码

  • 终止原始会话

  • 刷新原始窗口,看到您已注销