在 Spring 安全教程的这篇文章中,我们将讨论Spring 安全会话管理。我们将讨论 Spring 安全性的独特功能,这有助于我们高效和安全的会话管理。
春季安全会议
本文将讨论安全会话管理以及 spring 安全性如何帮助我们控制 HTTP 会话。Spring 安全性使用以下选项来控制 HTTP 会话功能
SessionManagementFilter
.SessionAuthneticationStrategy
这 2 个有助于 Spring 安全管理安全会话中的以下选项:
- 会话超时检测和处理。
- 并发会话(经过身份验证的用户可以同时打开的会话数)。
- 会话固定 – 处理会话
让我们详细了解这些选项
1. 何时创建会话
Spring 安全性提供了不同的选项来控制会话创建。它为我们提供了配置何时创建会话以及如何与会话交互的选项。以下是安全性中可用的选项,可以帮助我们配置和控制会话创建。
SessionCreationPolicy.ALWAYS
– 会话将始终创建(如果它不存在)。SessionCreationPolicy.NEVER
Spring Security永远不会创建HttpSession,但如果它已经存在,则会使用它(可通过应用程序服务器获得)HttpSession
SessionCreationPolicy.IF_REQUIRED
Spring Security 只会在需要时创建 HttpSession (默认配置。如果您不指定,Spring 安全性将使用此选项)SessionCreationPolicy.STATELESS
Spring Security永远不会创建一个HttpSession,它永远不会使用它来获取。SecurityContext
对于基于登录,应用程序适用于大多数情况,也是 Spring 安全性中的默认设置。对于典型的 Web 应用程序。要更改 Spring 安全性中的会话创建策略,我们可以通过覆盖 配置方法。SessionCreationPolicy. IF_REQUIRED
WebSecurityConfigurerAdapter
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
}
}
让我们记住以下要点
- 这些配置仅控制 Spring 安全行为,而不控制您的应用程序。您的应用程序可能使用不同的会话创建配置。
- 默认情况下,Spring 安全性将在需要时创建会话。它可以在 Spring 安全上下文之外使用应用程序创建的会话。(请记住,会话是由应用程序服务器创建的)。
- 这将确保 Spring 安全性不会创建任何会话,但这并不意味着您的应用程序不会创建任何会话。此策略仅适用于 Spring 安全上下文。您可能仍然会在您的应用程序中看到,所以不要认为 Spring 安全配置不起作用。
STATELESS
JSESIONID
请记住,Spring 安全性在 HTTP 会话的帮助下处理登录和注销请求。Spring安全不会使用cookie,每个请求都需要重新身份验证。我将在不同的帖子中介绍它,但另一个选项是使用 Spring 会话来集中管理您的Spring 会话。SessionCreationPolicy. STATELESS
1.1. Spring 安全性和 HTTP 会话
弹簧安全在很大程度上依赖于我们清楚地了解弹簧安全如何在内部使用该方法,这一点非常重要。下面是该过程的高级概述。HTTPSession
HTTPSession
- Spring 安全性使用 theand来存储经过身份验证的对象。经过身份验证的对象包含有关登录用户的信息。
SecurityContext
SecurityContextHolder
- 检索请求使用(检查源代码 SecurityContextPersistenceFilter)。Spring 安全性默认使用哪个使用来获取 HTTPSession。
SecurityContextPersistenceFilter
SecurityContext
SecurityContextRepository
HttpSessionSecurityContextRepository
HTTPRequest
- 它将安全上下文存储在。
SecurityContextHolder
- 这在整个请求生命周期中都可用。
SecurityContext
- 在请求周期结束时,将清除(检查最终块中的
SecurityContextPersistenceFilter
SecurityContextHolder
SecurityContextPersistenceFilter
)
2. 春季安全会话超时
会话超时后,如果他们提交具有无效会话 ID 的请求,我们可以将使用重定向到特定页面。要配置重定向 URL,我们可以通过覆盖来使用该方法。configure
WebSecurityConfigurerAdapter
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.invalidSessionUrl("/login");
}
}
如果你在配置中工作,你可以使用element来做到这一点:XML
session-manegement
<http>
...
<session-management invalid-session-url="/login" />
</http>
当您将 Spring 启动应用程序部署到独立服务器时,配置会话超时的方式与在任何其他战争部署中相同。
在 Tomcat 的情况下,我们可以通过在管理器元素上配置属性或使用 web.xml 中的元素来设置会话超时。请注意,第一个选项将影响部署到 Tomcat 实例的每个应用。maxInactiveInterval
server.xml
session-timeout
2.1. 使用 Spring 引导配置会话超时
Spring Boot 带有许多默认值,并且使用该文件可以更轻松地配置和自定义行为。若要控制会话超时,请使用以下属性application.properties
server.servlet.session.timeout= 120s
使用它时,请记住以下重要因素
- 如果您没有指定时间单位(在我们的例子中为 s),Spring boot 将假定第二个作为默认单位。
- 如果您使用的是 tomcat,它仅支持分钟精度,例如 187 将被视为 3 分钟。
3. Spring 安全并发会话控制
在某些应用程序(主要是金融应用程序)中,我们希望限制同一用户的多次登录。如果您想根据用户数量销售服务,并且希望仅允许基于许可证的指定用户(例如以用户帐户数量为基础出售的云服务),这也很有用。当用户通过身份验证并尝试再次重新进行身份验证时,我们的应用程序可以通过以下方式之一进行响应:
- 使现有会话失效并创建新的经过身份验证的会话。
- 继续退出会话并为新的登录尝试抛出/显示错误消息。
- 允许两个会话都存在,并允许用户从不同位置登录。
Spring 安全性支持通过会话管理限制同一用户的多次登录的功能。启用此功能的第一步是在应用程序中添加侦听器。在 Spring 引导应用程序中添加侦听器是一种 Bean 配置。侦听器将保持有关会话生命周期事件的春季安全性更新。HttpSessionEventPublisher
HttpSessionEventPublisher
/**
* We need this bean for the session management. Specially if we want to control the concurrent session-control support
* with Spring security.
* @return
*/
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
如果使用 xml 配置,请使用文件添加会话控制支持:web.xml
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>
3.1. 了解 Spring 安全并发会话控制
Spring 安全性并发会话控制是一项强大的功能,但在实施之前请确保您正确理解它。错误的理解可能会导致很多混乱,您可能会认为它没有按预期工作。Spring 安全部门在内部使用的重要类很少来强制执行此功能。以下是一些关键组件。
SessionRegistry
.ConcurrentSessionControlStrategy
HttpSessionEventPublisher
.SessionManagementFilter
ConcurrentSessionFilter
并发会话控制功能用于维护活动会话列表以及关联的经过身份验证的用户的信息。每次创建或销毁会话时,它都会通过 Spring 安全性实时更新此会话注册表。我们在本文前面配置了 Spring 安全性使用此事件发布来发布会话生命周期中的事件,并且相应地更新了 SessionRegistry。SessionRegistry
HTTP
HttpSessionEventPublisher
ConcurrentSessionControlStrategy
负责遍历新会话并强制实施并发会话策略。每次登录的客户尝试访问应用程序的安全部分时,都会检查用户的活动会话。过滤器将识别过期的会话,并通知用户其会话已过期。为了更好地理解,您还可以检查这些类的源代码。下面是一个高级工作流,概述了 Spring 安全并发会话控制的工作原理:SessionManagementFilter
SessionRegistry
ConcurrentSessionFilter
让我们看看并发会话功能的实际应用。
3.2. 通过 Spring 安全性限制每个用户的并发会话数
通过监听器配置,我们可以控制应用程序的会话多个会话功能。让我们举一个示例,我们希望每个客户最多允许 1 个会话。如果最大会话数超过 1,它将使 Spring 安全性的第一个会话无效。如何使用 Spring 安全配置完成此操作:HttpSessionEventPublisher
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.maximumSessions(1);
}
}
您可以从我们的GitHub 存储库下载该应用程序。应用程序启动后,执行以下步骤进行测试。
- 在 Firefox 中打开登录页面并使用有效的用户名和密码登录(请确保在此步骤之前创建了一个帐户。
- 打开 chrome 或任何其他浏览器(Firefox 除外)并使用相同的用户名和密码登录(在步骤 1 中使用)。
- 返回chrome浏览器并刷新或单击任何链接,您将在应用程序中看到类似的消息
这是来自弹簧安全的默认消息。Spring 安全性提供了配置URL的灵活性,当用户尝试进行额外登录时将调用该URL。要配置过期的会话重定向,我们可以使用该方法。expiredUrl
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.maximumSessions(1)
.expiredUrl("/login?invalid-session=true");
}
}
您可以在登录页控件中添加一些自定义错误消息。重新运行应用程序并按照上述步骤测试应用程序,在这种情况下,您将看到自定义错误消息,而不是 Spring 标准错误消息。
3.3. 禁用身份验证
对于默认配置(如第 3.1 节和第 3.2 节所述),第二次登录将导致第一次登录无效。这有时会引起混乱。想象一下,您正在工作,突然看到此消息是您意外在另一个浏览器中执行的登录。为了处理这些用例,Spring 安全性提供了一个选项,我们可以在其中向第二次尝试显示错误消息,而不是强制原始用户注销。我们可以在的帮助下启用此功能。maxSessionsPreventsLogin
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.maxSessionsPreventsLogin(true)
.maximumSessions(1)
.expiredUrl("/login?invalid-session=true");
}
}
将值设置为 for。在尝试使用此方法时必须小心。true
maxSessionsPreventsLogin
- 如果用户关闭窗口而不点击注销按钮,则在会话超时之前,他们将无法再次登录。
- 发生这种情况是因为它会在关闭浏览器窗口时删除 JSESSIONID,但是您仍然是底层应用程序的登录用户。
有关更多信息,请阅读Spring 安全文档。
3.4. 并发控制 – 常见问题
有了方法,请记住几个要点,因为如果您不清楚一些细节,它可能会导致很多混乱和问题maximumSessions
- 如果您使用的是自定义实例,请确保覆盖和方法。
UserDetails
equals()
hashCode()
- 默认情况下,Spring 安全实现使用 anto 存储。如果您使用的是没有 and 方法的自定义用户详细信息,它将无法正确匹配用户。此外,来自 Spring 安全性的默认对象为两者和方法提供了实现。
SessionRegistry
in-memory map
UserDetails
equals()
hashCode()
UserDetails
equals()
hashCode()
- 如果使用 Spring 安全性记住我功能进行登录,则不会强制执行并发控制。
- 在群集环境中,默认并发控制将不作为内存中实现工作。用户登录将特定于服务器,如果同一用户尝试登录到群集上的其他服务器上,则可以再次登录。您可以使用春季会话在自定义的帮助下处理此问题
SessionRegistry
SessionRegistry
- 如果应用程序服务器重新启动,则该将为空(记住它是一个),但已经使用有效会话登录的用户将登录。这将在用户登录时产生冲突,但 Spring 安全性会将用户标记为未登录。我们也可以在 custom 的帮助下解决此问题以从中心位置加载数据。
SessionRegistry
in-memory map
SessionRegistry
总结
在本文中,我们讨论了 Spring 安全会话管理以及如何使用 Spring 安全性控制会话。总而言之,我们在本文中讨论了以下要点。
- Spring 安全性如何管理会话以及如何使用 Spring 安全性控制会话创建策略。
- 如何并发控制与 Spring 安全性一起工作。
- 如何配置每个用户的并发会话数。
- Spring 安全并发控制的限制以及用于自定义它的选项很少。