vlambda博客
学习文章列表

读书笔记《spring-security-third-edition》会话管理

会话管理

本章讨论 Spring Security 的会话管理功能。它从一个 Spring Security 如何防御会话固定的示例开始。然后,我们将讨论如何利用并发控制来限制对按用户许可的软件的访问。我们还将了解如何将会话管理用于管理功能。最后,我们将探讨在 Spring Security 中如何使用 HttpSession 以及如何控制它的创建。

以下是本章将涉及的主题列表:

  • Session management/session fixation
  • Concurrency control
  • Managing logged in users
  • How HttpSession is used in Spring Security and how to control creation
  • How to use the DebugFilter class to discover where HttpSession was created

配置会话固定保护

由于我们使用的是安全命名空间风格的配置,会话固定保护已经为我们配置好了。如果我们想显式配置它以镜像默认设置,我们将执行以下操作:

    http.sessionManagement()
.sessionFixation().migrateSession();

会话固定保护是框架的一项功能,除非您尝试充当恶意用户,否则您很可能不会注意到它。我们将向您展示如何模拟会话窃取攻击;在我们这样做之前,重要的是要了解会话固定的作用以及它所阻止的攻击类型。

了解会话固定攻击

会话固定是一种攻击类型,恶意用户试图窃取系统中未经身份验证的用户的会话。这可以通过使用导致攻击者获得用户的唯一会话标识符(例如,JSESSIONID)的各种技术来完成。如果攻击者使用用户的 JSESSIONID 标识符创建 cookie 或 URL 参数,他们就可以访问用户的会话。

尽管这显然是一个问题,但通常情况下,如果用户未经身份验证,他们没有输入任何敏感信息。如果在用户通过身份验证后继续使用相同的会话标识符,这将成为一个更关键的问题。如果在身份验证后使用相同的标识符,攻击者现在可以访问经过身份验证的用户的会话,甚至无需知道他们的用户名或密码!

此时,您可能会难以置信地嗤之以鼻,并认为这在现实世界中极不可能发生。事实上,会话窃取攻击经常发生。我们建议您花一些时间阅读由 打开 Web 应用程序安全项目 ( OWASP) 组织 ( http://www.owasp.org/)。具体来说,您需要阅读 OWASP 前 10 名列表。攻击者和恶意用户是真实存在的,如果您不了解他们常用的技术并知道如何避免它们,他们可能会对您的用户、您的应用程序或您的公司造成非常真实的损害。

下图说明了会话固定攻击的工作原理:

读书笔记《spring-security-third-edition》会话管理

现在我们已经了解了这样的攻击是如何工作的,我们将看看 Spring Security 可以做些什么来防止它。

使用 Spring Security 防止会话固定攻击

如果我们能够防止用户在认证之前拥有的同一个会话在认证之后被使用,我们就可以有效地使攻击者对会话 ID 的了解变得毫无用处。 Spring Security 会话固定保护通过在用户通过身份验证时显式创建新会话并使其旧会话无效来解决此问题。

让我们看一下下面的图表:

读书笔记《spring-security-third-edition》会话管理

我们可以看到,一个新的过滤器 o.s.s.web.session.SessionManagementFilter 负责评估特定用户是否是新认证的。如果用户是新认证的,配置的 o.s.s.web.authentication.session.SessionAuthenticationStrategy 接口决定做什么。 o.s.s.web.authentication.session.SessionFixationProtectionStrategy 将创建一个新会话(如果用户已经拥有一个),并将现有会话的内容复制到新会话中。差不多就是这样——看起来很简单。但是,正如我们在上图中看到的,它有效地防止了恶意用户在对未知用户进行身份验证后重用会话 ID。

模拟会话固定攻击

此时,您可能希望了解模拟会话固定攻击所涉及的内容:

  1. You'll first need to disable session fixation protection in the SecurityConfig.java file by adding the sessionManagement() method as a child of the http element.
您应该从以下代码开始 第 14.00 章-日历

让我们看一下下面的代码片段:

    //src/main/java/com/packtpub/springsecurity/configuration/
SecurityConfig.java

http.sessionManagement().sessionFixation().none();
您的代码现在应该看起来像 第 14.01 章-日历
  1. Next, you'll need to open two browsers. We'll initiate the session in Google Chrome, steal it from there, and our attacker will log in using the stolen session in Firefox. We will use the Google Chrome and the Firefox web developer add-on in order to view and manipulate cookies. The Firefox web developer add-on can be downloaded from https://addons.mozilla.org/en-US/firefox/addon/web-developer/. Google Chrome's web developer tools are built-in.
  2. Open the JBCP calendar home page in Google Chrome.

  1. Next, from the main menu, navigate to Edit | Preferences | Under the Hood. In the Privacy category, press the Content Settings... button. Next, in Cookies Settings, press the All Cookies and Site Data... button. Finally, enter localhost into the Search field, as follows:
读书笔记《spring-security-third-edition》会话管理
  1. Select the JSESSIONID cookie, copy the value of Content to the clipboard, and log in to the JBCP calendar application. If you repeat the View Cookie Information command, you'll see that JSESSIONID did not change after you logged in, making you vulnerable to a session fixation attack!
  2. In Firefox, open the JBCP calendar website. You will have been assigned a session cookie, which you can view by using Ctrl + F2 to open the bottom Cookie console. Then type in cookie list [enter] to bring up cookies for the current page.
  3. To complete our hack, we'll click on the Edit Cookie option and paste in the JSESSIONID cookie that we copied to the clipboard from Google Chrome, as shown in the following screenshot:
读书笔记《spring-security-third-edition》会话管理
  1. Keep in mind that newer versions of Firefox include web developer tools, too. However, you will need to ensure that you are using the extension and not the built-in one, as it provides additional capabilities.

我们的会话固定破解完成了!如果您现在在 Firefox 中重新加载页面,您将看到您以使用 Google Chrome 登录的同一用户身份登录,但不知道用户名和密码。你害怕恶意用户了吗?

现在,重新启用会话固定保护并再次尝试此练习。您会看到,在这种情况下,用户登录后 JSESSIONID 会发生变化。根据我们对会话固定攻击如何发生的理解,这意味着我们降低了毫无戒心的用户跌倒的可能性此类攻击的受害者。很棒的工作!

谨慎的开发人员应该注意,窃取会话 cookie 的方法有很多,其中一些方法(例如 XSS)甚至可能使受会话固定保护的站点易受攻击。请咨询 OWASP 站点以获取有关防止此类攻击的其他资源。

比较会话固定保护选项

session-fixation-protection 属性具有以下三个选项,可让您更改其行为,如下所示:

属性值

说明

无()

此选项禁用会话固定保护并且(除非其他 sessionManagement() 属性是非默认的)不配置 SessionManagementFilter

migrateSession()

当用户通过身份验证并分配新会话时,它确保将旧会话的所有属性移动到新会话。

newSession()

当用户通过身份验证时,会创建一个新会话,并且不会迁移旧(未经身份验证)会话的任何属性。

在大多数情况下,migrateSession() 的默认行为适用于希望在用户通过身份验证后保留用户会话的重要属性(例如点击兴趣和购物车)的网站。

限制每个用户的并发会话数

在软件行业,软件通常按用户销售。这意味着,作为软件开发人员,我们有兴趣确保每个用户只存在一个会话,以打击帐户共享。 Spring Security 的并发会话控制确保单个用户不能同时拥有超过固定数量的活动会话(通常是一个)。确保执行此最大限制涉及多个组件协同工作以准确跟踪用户会话活动的变化。

让我们配置该功能,查看它的工作原理,然后进行测试!

配置并发会话控制

现在我们已经了解了并发会话控制中涉及的不同组件,设置它应该更有意义。下面我们来看看配置并发会话控制的步骤:

  1. Firstly, you update your security.xml file as follows:
        // src/main/java/com/packtpub/springsecurity/configuration/
SecurityConfig.java

http.sessionManagement().maximumSessions(1)
  1. Next, we need to enable o.s.s.web.session.HttpSessionEventPublisher in the SecurityConfig.java deployment descriptor, so that the servlet container will notify Spring Security (through HttpSessionEventPublisher) of session life cycle events, as follows:
        // src/main/java/com/packtpub/springsecurity/configuration/ 
SecurityConfig.java

@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}

有了这两个配置位,现在将激活并发会话控制。让我们看看它实际上做了什么,然后我们将演示如何对其进行测试。

了解并发会话控制

并发会话控制使用 o.s.s.core.session.SessionRegistry 来维护活动 HTTP 会话的列表以及与其关联的经过身份验证的用户。随着会话的创建和过期,注册表会根据 HttpSessionEventPublisher 发布的会话生命周期事件实时更新,以跟踪每个经过身份验证的用户的活动会话数。

参考下图:

读书笔记《spring-security-third-edition》会话管理

SessionAuthenticationStrategy 的扩展,o.s.s.web.authentication.session.ConcurrentSessionControlStrategy 是跟踪新会话的方法和实际执行并发控制的方法。每次用户访问受保护的站点时,SessionManagementFilter 用于对照 SessionRegistry 检查活动会话。如果用户的活动会话不在 SessionRegistry 中跟踪的活动会话列表中,则最近最少使用的会话将立即过期。

修改后的并发会话控制过滤器链中的次要参与者是 o.s.s.web.session.ConcurrentSessionFilter。此过滤器将识别过期的会话(通常是由 servlet 容器或 ConcurrentSessionControlStrategy 接口强制过期的会话)并通知用户他们的会话已过期。

既然我们已经了解了并发会话控制的工作原理,我们应该很容易重现执行它的场景。

Your code should now look like chapter14.02-calendar.

测试并发会话控制

正如我们在验证会话固定保护时所做的那样,我们需要通过执行以下步骤来访问两个 Web 浏览器:

  1. In Google Chrome, log in to the site as [email protected]/user1.
  2. Now, in Firefox, log in to the site as the same user.
  3. Finally, go back to Google Chrome and take any action. You will see a message indicating that your session has expired, as shown in the following screenshot:
读书笔记《spring-security-third-edition》会话管理

如果您正在使用此应用程序并收到此消息,您可能会感到困惑。这是因为通知一次只有一个用户可以访问应用程序显然不是一种友好的方法。但是,它确实说明会话已被软件强制过期。

并发会话控制对于 Spring Security 的新用户来说往往是一个非常难以掌握的概念。许多用户在没有真正了解它的工作原理和好处的情况下尝试实施它。如果您尝试启用这个强大的功能,但它似乎没有按预期工作,请确保您已正确配置所有内容,然后查看本节中的理论解释——希望它们能帮助您了解可能发生的情况是错的!

当会话过期事件发生时,我们可能应该将用户重定向到登录页面,并向他们提供一条消息以指示发生了什么问题。

配置过期会话重定向

幸运的是,当用户被并发会话控制标记时,有一种简单的方法可以将用户引导到友好页面(通常是登录页面)——只需指定 expired-url 属性并将其设置为有效页面在您的应用程序中。更新您的 security.xml 文件,如下所示:

    //src/main/java/com/packtpub/springsecurity/configuration/SecurityConfig.java

http.sessionManagement()
.maximumSessions(1)
.expiredUrl("/login/form?expired")
;

在我们的应用程序中,这会将用户重定向到标准登录表单。然后,我们将使用查询参数显示一条友好消息,指示我们确定他们有多个活动会话,并且应该再次登录。更新您的 login.html 页面以使用此参数来显示我们的消息:

    //src/main/resources/templates/login.html

...
<div th:if="${param.expired != null}" class="alert alert-success">
<strong>Session Expired</strong>
<span>You have been forcibly logged out due to multiplesessions
on the same account (only one activesession per user is allowed).</span>
</div>
<label for="username">Username</label>

继续尝试,使用 Google Chrome 和 Firefox 以用户 [email protected]/admin1 的身份登录。这一次,您应该会看到一个带有自定义错误消息的登录页面。

您的代码现在应该看起来像 第 14.03 章-日历

并发控制的常见问题

使用同一用户登录不会触发注销事件的常见原因有几个。第一个发生在使用自定义 UserDetails 时(就像我们在 第 3 章自定义身份验证),而 equals 和 hashCode 方法没有正确实现。这是因为默认的 SessionRegistry 实现使用内存映射来存储 UserDetails。为了解决这个问题,您必须确保您已正确实现 hashCode 和 equals 方法。

第二个问题发生在重新启动应用程序容器时,而用户会话被持久化到磁盘。当容器启动备份时,已经使用有效会话登录的用户会登录。但是,用于确定用户是否已登录的 SessionRegistry 的内存映射in 将是空的。这意味着 Spring Security 将报告用户未登录,即使用户已登录。要解决此问题,需要自定义 SessionRegistry 并禁用容器内的会话持久性,或者您必须实现特定于容器的方法以确保将持久化会话填充到内存映射中在启动时。

还有一个原因是,在撰写本文时,还没有为记住我功能实现并发控制。如果用户通过记住我的身份验证,则不会强制执行该并发控制。有一个 JIRA 来实现此功能,因此如果您的应用程序需要记住我和并发控制,请参阅它以获取任何更新:https://jira.springsource.org/browse/SEC-2028

我们将讨论的最后一个常见原因是并发控制在具有默认 SessionRegistry 实现的集群环境中不起作用。如前所述,默认实现使用内存映射。这意味着如果 user1 登录到应用程序服务器 A,他们登录的事实将与该服务器相关联。因此,如果 user1 然后向应用服务器 B 进行身份验证,则应用服务器 B 将不知道先前关联的身份验证。

阻止身份验证而不是强制注销

如果用户已经有会话,Spring Security 还可以阻止用户登录应用程序。这意味着Spring Security不会强制原来的用户退出,而是阻止第二个用户登录。配置变化可以看如下:

    //src/main/java/com/packtpub/springsecurity/configuration/SecurityConfig.java

http.sessionManagement()
.maximumSessions(1)
.expiredUrl("/login/form?expired")
.maxSessionsPreventsLogin(true);

使用 Google Chrome 进行更新并登录日历应用程序。现在,尝试使用同一用户使用 Firefox 登录日历应用程序。您应该会从我们的 login.html 文件中看到我们的自定义错误消息。

您的代码现在应该看起来像 第 14.04 章-日历

这种方法有一个缺点,如果不加思索,可能并不明显。尝试在不注销的情况下关闭 Google Chrome,然后再次打开它。现在,尝试再次登录应用程序。您将观察到您无法登录。这是因为当浏览器关闭时,JSESSIONID cookie 被删除。但是,应用程序并没有意识到这一点,因此用户仍然被认为是经过身份验证的。您可以将其视为一种内存泄漏,因为 HttpSession 仍然存在但没有指向它的指针(JSESSIONID cookie 消失了)。直到会话超时,我们的用户才能再次进行身份验证。幸运的是,一旦会话超时,我们的 SessionEventPublisher 接口将从我们的 SessionRegistry 接口中删除用户。我们可以从中得出的结论是,如果用户忘记注销并关闭浏览器,他们将无法登录应用程序,直到会话超时。

就像在 第 7 章记住我的服务,如果浏览器在关闭浏览器后仍决定记住会话,则此实验可能无法运行。通常,如果插件或浏览器配置为恢复会话,就会发生这种情况。在这种情况下,您可能需要删除 JSESSIONID cookie 手动模拟浏览器被关闭。

并发会话控制的其他好处

并发会话控制的另一个好处是 SessionRegistry 用于跟踪活动(以及,可选地,过期)会话。这意味着我们可以通过执行以下步骤获取有关系统中存在哪些用户活动的运行时信息(至少对于经过身份验证的用户):

  1. You can even do this if you don't want to enable concurrent session control. Simply set maximumSessions to -1, and session tracking will remain enabled, even though no maximum will be enforced. Instead, we will use the explicit bean configuration provided in the SessionConfig.java file of this chapter, as follows:
        //src/main/java/com/packtpub/springsecurity/configuration/
SessionConfig.java

@Bean
public SessionRegistry sessionRegistry(){
return new SessionRegistryImpl();
}
  1. We have already added the import of the SessionConfig.java file to the SecurityConfig.java file. So, all that we need to do is reference the custom configuration in our SecurityConfig.java file. Go ahead and replace the current sessionManagement and maximumSessions configurations with the following code snippet:
        //src/main/java/com/packtpub/springsecurity/configuration/
SecurityConfig.java

http.sessionManagement()
.maximumSessions(-1)
.sessionRegistry(sessionRegistry)
.expiredUrl("/login/form?expired")
.maxSessionsPreventsLogin(true);
您的代码现在应该看起来像 第 14.05 章-日历

现在,我们的应用程序将允许对同一用户进行无限数量的身份验证。但是,我们可以使用 SessionRegistry 来强制注销用户。让我们看看如何使用这些信息来增强用户的安全性。

显示用户的活动会话

您可能已经看到有多少网站允许用户查看和强制注销其帐户的会话。我们可以轻松地使用这种强制注销功能来做同样的事情。我们已经提供了 UserSessionController,它获取当前登录用户的活动会话。你可以看到如下实现:

    //src/main/java/com/packtpub/springsecurity/web/controllers/
UserSessionController.java

@Controller
public class UserSessionController {
private final SessionRegistry sessionRegistry;
@Autowired
public UserSessionController(SessionRegistry sessionRegistry) {
this.sessionRegistry = sessionRegistry;
}
@GetMapping("/user/sessions/")
public String sessions(Authentication authentication, ModelMap model) {
List<SessionInformation> sessions = sessionRegistry.getAllSessions
(authentication.getPrincipal(), false);
model.put("sessions", sessions);
return "user/sessions";
}
@DeleteMapping(value="/user/sessions/{sessionId}")
public String removeSession(@PathVariable String sessionId,
RedirectAttributes redirectAttrs) {
SessionInformation sessionInformation = sessionRegistry.
getSessionInformation(sessionId);
if(sessionInformation != null) {
sessionInformation.expireNow();
}
       redirectAttrs.addFlashAttribute("message", "Session was removed");
return "redirect:/user/sessions/";
}
}

我们的 session 方法将使用 Spring MVC 自动获取当前 Spring Security Authentication。如果我们不使用 Spring MVC,我们还可以从 SecurityContextHolder 获取当前的 Authentication,如 第 3 章自定义身份验证。然后使用主体获取当前用户的所有 SessionInformation 对象。通过迭代 sessions.html 文件中的 SessionInformation 对象可以轻松显示信息,如下所示:

//src/main/resources/templates/sessions.html

...
<tr th:each="session : ${sessions}">
<td th:text="${#calendars.format(session.lastRequest, 'yyyy-MM-dd HH:mm')}">
</td>
<td th:text="${session.sessionId}"></td>
<td>
<form action="#" th:action="@{'/user/sessions/{id}'(id=${session.sessionId})}"
th:method="delete" cssClass="form-horizontal">
<input type="submit" value="Delete" class="btn"/>
</form>
</td>
</tr>
...

您现在可以安全地启动 JBCP 日历应用程序并使用 Google Chrome 中的 [email protected]/user1 登录它。现在,使用 Firefox 登录并单击右上角的 [email protected] 链接。然后,您将在显示屏上看到两个会话,如以下屏幕截图所示:

读书笔记《spring-security-third-edition》会话管理

在 Firefox 中,单击第一个会话的 Delete 按钮。这会将请求发送到 UserSessionsControllerdeleteSession 方法。这表明应该终止会话。现在,导航到 Google Chrome 中的任何页面。您将看到自定义消息说会话已被强制终止。虽然消息可以使用更新,但我们看到这是一个很好的功能,可以让用户终止其他活动会话。

其他可能的用途包括允许管理员列出和管理所有活动会话、显示站点上活动用户的数量,甚至扩展信息以包括 IP 地址或位置信息等内容。

Spring Security 如何使用 HttpSession 方法?

我们已经讨论过 Spring Security 如何使用 SecurityContextHolder 来确定当前登录的用户。但是,我们还没有解释 SecurityContextHolder 如何被 Spring Security 自动填充。其秘诀在于 o.s.s.web.context.SecurityContextPersistenceFilter 过滤器和 o.s.s.web.context.SecurityContextRepository 接口。让我们看一下下面的图表:

读书笔记《spring-security-third-edition》会话管理

以下是对上图中显示的每个步骤的说明:

  1. At the beginning of each web request, SecurityContextPersistenceFilter is responsible for obtaining the current SecurityContext implementation using SecurityContextRepository.
  2. Immediately afterwards, it sets SecurityContext on SecurityContextHolder.
  3. For the remainder of the web request, SecurityContext is available via SecurityContextHolder. For example, if a Spring MVC controller or CalendarService wanted to access SecurityContext, it could use SecurityContextHolder to access it.
  4. Then, at the end of each request, SecurityContextPersistenceFilter gets the SecurityContext from SecurityContextHolder.
  5. Immediately afterwards, SecurityContextPersistenceFilter saves SecurityContext in SecurityContextRepository. This ensures that if SecurityContext is updated at any point during the web requests (that is, when a user creates a new account, as done in Chapter 3, Custom Authentication) SecurityContext is saved.
  6. Lastly, SecurityContextPersistenceFilter clears SecurityContextHolder.

现在出现的问题是这与 HttpSession 有什么关系?这一切都由默认的 SecurityContextRepository 实现捆绑在一起,该实现使用 HttpSession

HttpSessionSecurityContextRepository 接口

SecurityContextRepository的默认实现,o.s.s.web.context.HttpSessionSecurityContextRepository,使用HttpSession来检索和存储当前的SecurityContext执行。没有提供开箱即用的其他 SecurityContextRepository 实现。然而,由于 HttpSession 的使用被抽象在 SecurityContextRepository 接口后面,如果我们愿意,我们可以很容易地编写自己的实现。

配置 Spring Security 如何使用 HttpSession

Spring Security 能够配置 Spring Security 何时创建会话。这可以通过 http 元素的 create-session 属性来完成。下表总结了这些选项:

属性值

说明

如果需要

只有在需要时,Spring Security 才会创建一个会话(默认值)。

总是

如果会话不存在,Spring Security 将主动创建会话。

从不

Spring Security 永远不会创建会话,但如果应用程序确实创建了会话,则会使用它。这意味着如果有一个 HttpSession 方法,SecurityContext 将被持久化或从中检索。

无状态

Spring Security 不会创建会话,并且会忽略会话以获取 Spring Authentication。在这种情况下,将使用 NullSecurityContextRepository,它始终声明当前 SecurityContextnull

在实践中,控制会话创建可能比最初看起来更困难。这是因为属性只控制 Spring Security 的 HttpSession 使用的一个子集。它不适用于应用程序中的任何其他组件,例如 JSP。为了帮助确定 HttpSession 方法的创建时间,我们可以添加 Spring Security 的 DebugFilter

使用 Spring Security 的 DebugFilter 进行调试

下面我们来看看下面的步骤,了解如何使用 Spring Security 的 DebugFilter 进行调试:

  1. Update your SecurityConfig.java file to have a session policy of NEVER. Also, add the debug flag to true on the @EnableWebSecurity annotation, so that we can track when the session was created. The updates can be seen as follows:
        //src/main/java/com/packtpub/springsecurity/configuration/
SecurityConfig.java

@Configuration
@Enable WebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER);
  1. When you start up the application, you should see something similar to the following code written to standard output. If you have not already, ensure that you have logging enabled across all levels of the Spring Security debugger category:
            ********************************************************************  
********** Security debugging is enabled. *************
********** This may include sensitive information. *************
********** Do not use in a production system! *************
********************************************************************
  1. Now, clear out your cookies (this can be done in Firefox with Shift + Ctrl + Delete), start up the application, and navigate directly to http://localhost:8080. When we look at the cookies, as we did earlier in the chapter, we can see that JSESSIONID is created even though we stated that Spring Security should never create HttpSession. Look at the logs again, and you will see a call stack of the code that created HttpSession as follows:
            ************************************************************
2017-07-25 18:02:31.802 INFO 71368 --- [nio-8080-exec-1]
Spring Security Debugger :
************************************************************
New HTTP session created: 2A708D1C3AAD508160E6189B69D716DB
  1. In this instance, our JSP page is responsible for creating the new HttpSession method. In fact, all JSPs will create a new HttpSession method by default unless you include the following code at the top of each JSP:
        <%@ page session="false" %>

DebugFilter 还有许多其他用途,我们鼓励您自行探索,例如,确定请求何时匹配特定 URL、正在调用哪些 Spring Security 过滤器等等上。

概括

阅读本章后,您应该熟悉 Spring Security 如何管理会话并防止会话固定攻击。我们也知道如何使用 Spring Security 的并发控制来防止同一个用户被多次认证。

我们还探索了使用并发控制来允许用户终止与其帐户关联的会话。此外,我们还了解了如何配置 Spring Security 的会话创建。我们还介绍了如何使用 Spring Security 的 DebugFilter 过滤器来解决与 Spring 相关的问题。

我们还了解了安全性,包括确定 HttpSession 方法的创建时间以及创建它的原因。

我们对 Spring Security 的会话管理的讨论到此结束。在下一章中,我们将讨论有关将 Spring Security 与其他框架集成的一些细节。