在数据库中存储表单登录会话
Posted
技术标签:
【中文标题】在数据库中存储表单登录会话【英文标题】:Storing Form Login Sessions in a Database 【发布时间】:2014-06-18 12:22:22 【问题描述】:我的 Spring 服务器上的安全上下文使用 Spring Security 的内置表单登录实现。目前,登录会话由 servlet 容器本地存储在内存中。我想用我的 Spring Data Mongo 存储库之一替换 HttpSessions 的存储和检索方式。我在 Java 配置中寻找一个用于会话管理的“插槽”,但没有找到任何东西。需要明确的是,我正在寻找相当于 UserDetailsService 的,但用于会话。
下面是我的安全配置类中Java配置的相关sn-p:
...
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.formlogin()
.loginProcessingUrl("/authentication/login")
.successHandler(successHandler)
.usernameParameter("username")
.passwordParameter("password")
.failureUrl("/login?error")
.loginPage("/login")
.and()
.logout()
.logoutUrl("/authentication/logout")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.logoutSuccessUrl("/login")
.and()
...
据我所知,我没有做任何特别奇怪的事情。它可能不相关,但是当我说我找不到正确的配置槽时,我想准确地展示我正在查看的内容。
我仔细查看了SecurityContextPersistenceFilter 的源代码,这似乎是 Spring Security 的过滤器链中负责检索和存储 HttpSessions 的过滤器。它将会话检索委托给HttpServletRequest 中的getSession()
调用,并将会话存储委托给注入的SecurityContextRepository 中的saveContext()
。
为了正确替换默认的服务器本地会话存储机制,我看到了三种方法。
将 Spring Data 支持的安全上下文存储库插入持久性过滤器。然后,包装传入请求以实现自定义getSession()
行为,该行为查询自定义安全上下文存储库而不是本地存储。然后,内置的持久性过滤器将“做正确的事”。
设置一个 ObjectPostProcessor 以将默认过滤器替换为直接使用我的 Spring Data 存储库而不是调用 getSession()
或使用安全上下文存储库的自定义 SecurityContextPersistenceFilter。实际上我以前从未使用过对象后处理器,所以如果这不是它们的用途,请告诉我。
我不在考虑最后一个选项,但值得一提。我认为在所有魔法的背后,Spring Security 真正委托给了 servlet 容器的会话存储实现。因此,将后备存储更改为 Mongo 的一种方法是使用类似 Tomcat 的 Manager 接口来自定义会话持久性行为。这不是我想做的事情,因为它与 Spring 完全分离,我失去了通过依赖注入使用我的服务的能力,并且它完全依赖于容器,因此很难随心所欲地改变。
李>我确信删除会话存储并用数据库替换它是 Spring 服务器的一个相当普遍的要求。通常是怎么做的?如果我只是缺少一个配置选项,我很想看看它的位置。否则,我正在寻找关于采取哪条路线(以及为什么)的建议。
【问题讨论】:
【参考方案1】:在Spring 3
,地点在SessionManagement。
基本上,您定义会话过滤器并专门化会话策略或会话注册表。
会话注册表负责处理会话无效和创建。在这一点上,你可以坚持任何你需要坚持的东西。
这种方法的缺点是它需要您在web.xml
文件中声明会话事件发布者或您处理所有事情。
一个例子是实现SessionRegistry
和SessionAuthenticationStrategy
。从那里,当用户进行身份验证或执行getSession(true)
(或使其无效)时,它将到达代码,您可以在那里对其采取行动。您的策略将注入您的会话注册表。如果用户通过身份验证链进行身份验证,它将达到您的策略,该策略会将会话传递给您的注册表。
另一种方法是添加您自己的自定义过滤器。扩展GenericFilterBean
的类。然后注册:
<security:custom-filter ref="customSessionFilter" after="LAST" />
在此示例中,它将最后执行。这很有用,因为您可以检查活动会话或成功通过身份验证的用户。
【讨论】:
你能再具体一点吗?当您说“会话过滤器”时,您会想到哪个过滤器类?该文档建议添加一个 ConcurrencySessionControlFilter 以能够防止主体同时对同一应用程序进行超过指定次数的身份验证。我对管理并发会话不感兴趣(还)。您是否建议可以使用此过滤器的会话注册表来自定义会话持久性,而我应该忽略该建议使用? 下次有机会我会继续尝试。如果它确实让我插入我的 Spring Data 存储库以进行会话存储,我会立即接受它。首先只是想确保它有效。 这确实是会话持久性配置缺少的“槽”。谢谢!【参考方案2】:类似于您的选项 #3 而不依赖容器特定接口的方法是使用 Spring Session 和 MongoDB 支持的 SessionRepository
实现。
这将处理持久的所有 HTTP 会话数据,而不仅仅是特定于 Spring-security 的位。
【讨论】:
以上是关于在数据库中存储表单登录会话的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 javascript 而不是 Django 会话将表单数据(Django 表单)存储到浏览器的本地存储?