如何在没有会话的情况下使用 Spring Security?
我正在使用 Spring Security 构建一个 Web 应用程序,该应用程序将运行在 Amazon EC2 上并使用 Amazon 的弹性负载均衡器。不幸的是,ELB 不支持粘性会话,因此我需要确保我的应用程序在没有会话的情况下正常工作。
到目前为止,我已经设置 RememberMeServices 通过 cookie 分配令牌,这工作正常,但我希望 cookie 在浏览器会话中过期(例如,当浏览器关闭时)。
我必须想象我不是第一个想要在没有会话的情况下使用 Spring Security 的人......有什么建议吗?
I am building a web application with Spring Security that will live on Amazon EC2 and use Amazon's Elastic Load Balancers. Unfortunately, ELB does not support sticky sessions, so I need to ensure my application works properly without sessions.
So far, I have setup RememberMeServices to assign a token via a cookie, and this works fine, but I want the cookie to expire with the browser session (e.g. when the browser closes).
I have to imagine I'm not the first one to want to use Spring Security without sessions... any suggestions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
在 Spring Security 3 中 Java配置,可以使用HttpSecurity.sessionManagement():
In Spring Security 3 with Java Config, you can use HttpSecurity.sessionManagement():
今天,我们花了 4-5 个小时来解决同一问题(将自定义 SecurityContextRepository 注入 SecurityContextPersistenceFilter)。最后,我们想通了。
首先,在 Spring Security ref 的 8.3 节中。 doc,有一个 SecurityContextPersistenceFilter bean 定义
在这个定义之后,有这样的解释:
“或者,您可以提供 SecurityContextRepository 接口的 null 实现,这将阻止存储安全上下文,即使在请求期间已经创建了会话。”
我们需要将自定义的 SecurityContextRepository 注入 SecurityContextPersistenceFilter 中。因此,我们只需使用自定义实现更改上面的 bean 定义,并将其放入安全上下文中。
当我们运行应用程序时,我们跟踪日志并发现 SecurityContextPersistenceFilter 没有使用我们的自定义实现,而是使用 HttpSessionSecurityContextRepository。
在我们尝试了一些其他事情之后,我们发现我们必须为我们的自定义 SecurityContextRepository impl 提供“http”命名空间的“security-context-repository-ref”属性。如果您使用“http”命名空间并希望注入自己的 SecurityContextRepository impl,请尝试“security-context-repository-ref”属性。
当使用“http”命名空间时,单独的 SecurityContextPersistenceFilter 定义将被忽略。正如我在上面复制的,参考文档。没有说明这一点。
如果我误解了这些事情,请纠正我。
We worked on the same issue (injecting a custom SecurityContextRepository to SecurityContextPersistenceFilter) for 4-5 hours today. Finally, we figured it out.
First of all, in the section 8.3 of Spring Security ref. doc, there is a SecurityContextPersistenceFilter bean definition
And after this definition, there is this explanation:
"Alternatively you could provide a null implementation of the SecurityContextRepository interface, which will prevent the security context from being stored, even if a session has already been created during the request."
We needed to inject our custom SecurityContextRepository into the SecurityContextPersistenceFilter. So we simply changed the bean definition above with our custom impl and put it into the security context.
When we run the application, we traced the logs and saw that SecurityContextPersistenceFilter was not using our custom impl, it was using the HttpSessionSecurityContextRepository.
After a few other things we tried, we figured out that we had to give our custom SecurityContextRepository impl with the "security-context-repository-ref" attribute of "http" namespace. If you use "http" namespace and want to inject your own SecurityContextRepository impl, try "security-context-repository-ref" attribute.
When "http" namespace is used, a seperate SecurityContextPersistenceFilter definition is ignored. As I copied above, the reference doc. does not state that.
Please correct me if I misunderstood the things.
在 Spring Securitiy 3.0 中似乎更加容易。如果您使用名称空间配置,则可以简单地执行以下操作:
或者您可以将 SecurityContextRepository 配置为 null,这样就不会保存任何内容 以及。
It seems to be even easier in Spring Securitiy 3.0. If you're using namespace configuration, you can simply do as follows:
Or you could configure the SecurityContextRepository as null, and nothing would ever get saved that way as well.
看一下
SecurityContextPersistenceFilter
类。它定义了如何填充SecurityContextHolder
。默认情况下,它使用 HttpSessionSecurityContextRepository 来存储 http 会话中的安全上下文。我已经使用自定义的 SecurityContextRepository 非常轻松地实现了此机制。
请参阅下面的
securityContext.xml
:Take a look at
SecurityContextPersistenceFilter
class. It defines how theSecurityContextHolder
is populated. By default it usesHttpSessionSecurityContextRepository
to store security context in http session.I have implemented this mechanism quite easily, with custom
SecurityContextRepository
.See the
securityContext.xml
below:实际上
create-session="never"
并不意味着完全无状态。 Spring Security 问题管理中存在一个问题。Actually
create-session="never"
doesn't mean being completely stateless. There's an issue for that in Spring Security issue management.编辑:从 Spring Security 3.1 开始,有一个
STATELESS
选项可以用来代替所有这些。请参阅其他答案。原始答案保留在下面供后代使用。在与这个答案中发布的众多解决方案进行斗争之后,为了尝试在使用
命名空间配置时让某些东西正常工作,我终于找到了一种真正适合我的用例的方法。我实际上并不要求 Spring Security 不启动会话(因为我在应用程序的其他部分使用会话),只是它根本不“记住”会话中的身份验证(应该重新检查)每个请求)。首先,我无法弄清楚如何执行上述“空实现”技术。目前尚不清楚您是否应该将 securityContextRepository 设置为
null
还是无操作实现。前者不起作用,因为在SecurityContextPersistenceFilter.doFilter()
中抛出了NullPointerException
。至于无操作实现,我尝试以我能想象到的最简单的方式实现:这在我的应用程序中不起作用,因为一些奇怪的
ClassCastException
与response_< /代码> 类型。
即使假设我确实找到了一个可行的实现(通过简单地不在会话中存储上下文),仍然存在如何将其注入到由
配置构建的过滤器中的问题。您不能简单地替换SECURITY_CONTEXT_FILTER
位置的过滤器,按照 文档。我发现连接到在幕后创建的SecurityContextPersistenceFilter
的唯一方法是编写一个丑陋的ApplicationContextAware
bean:无论如何,对于实际有效的解决方案,尽管非常黑客式的。只需使用
Filter
来删除HttpSessionSecurityContextRepository
在执行其操作时查找的会话条目:然后在配置中:
EDIT: As of Spring Security 3.1, there is a
STATELESS
option that can be used instead of all this. See the other answers. Original answer kept below for posterity.After struggling with the numerous solutions posted in this answer, to try to get something working when using the
<http>
namespace config, I finally found an approach that actually works for my use case. I don't actually require that Spring Security doesn't start a session (because I use session in other parts of the application), just that it doesn't "remember" authentication in the session at all (it should be re-checked every request).To begin with, I wasn't able to figure out how to do the "null implementation" technique described above. It wasn't clear whether you are supposed to set the securityContextRepository to
null
or to a no-op implementation. The former does not work because aNullPointerException
gets thrown withinSecurityContextPersistenceFilter.doFilter()
. As for the no-op implementation, I tried implementing in the simplest way I could imagine:This doesn't work in my application, because of some strange
ClassCastException
having to do with theresponse_
type.Even assuming I did manage to find an implementation that works (by simply not storing the context in session), there is still the problem of how to inject that into the filters built by the
<http>
configuration. You cannot simply replace the filter at theSECURITY_CONTEXT_FILTER
position, as per the docs. The only way I found to hook into theSecurityContextPersistenceFilter
that is created under the covers was to write an uglyApplicationContextAware
bean:Anyway, to the solution that actually does work, albeit very hackish. Simply use a
Filter
that deletes the session entry that theHttpSessionSecurityContextRepository
looks for when it does its thing:Then in the configuration:
只是一个快速说明:它是“create-session”而不是“create-sessions”
create-session
控制创建 HTTP 会话的急切程度。
如果未设置,则默认为“ifRequired”。其他选项是“总是”和“从不”。
此属性的设置会影响 HttpSessionContextIntegrationFilter 的allowSessionCreation 和forceEagerSessionCreation 属性。除非该属性设置为“never”,否则allowSessionCreation 将始终为true。除非将其设置为“始终”,否则forceEagerSessionCreation 为“假”。
因此,默认配置允许会话创建,但不强制创建。例外情况是,如果启用并发会话控制,则无论此处的设置是什么,forceEagerSessionCreation 将设置为 true。使用“never”会在 HttpSessionContextIntegrationFilter 初始化期间导致异常。
有关会话使用的具体细节,HttpSessionSecurityContextRepository javadoc 中有一些很好的文档。
Just a quick note: it's "create-session" rather than "create-sessions"
create-session
Controls the eagerness with which an HTTP session is created.
If not set, defaults to "ifRequired". Other options are "always" and "never".
The setting of this attribute affect the allowSessionCreation and forceEagerSessionCreation properties of HttpSessionContextIntegrationFilter. allowSessionCreation will always be true unless this attribute is set to "never". forceEagerSessionCreation is "false" unless it is set to "always".
So the default configuration allows session creation but does not force it. The exception is if concurrent session control is enabled, when forceEagerSessionCreation will be set to true, regardless of what the setting is here. Using "never" would then cause an exception during the initialization of HttpSessionContextIntegrationFilter.
For specific details of the session usage, there is some good documentation in the HttpSessionSecurityContextRepository javadoc.
现在 ELB 支持粘性会话,我想从 2016 年开始。
而且还可以将会话存储在 Redis 中。
Now ELB supports sticky sessions, I think from 2016.
But also it's possible to store your sessions in Redis.