Spring安全-无法注销
我使用基本 HTTP 身份验证通过基本 LDAP 授权改造了我的 GWT/GXT 应用程序。当我启动新浏览器时,它运行良好 - 我收到提示并获得针对公司 LDAP 的授权。我的问题 - 除非关闭/重新打开浏览器,否则我无法注销。我可以调试并查看如何调用 SecurityContextLogoutHandler#logout
并执行以下代码
if (invalidateHttpSession) {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
}
SecurityContextHolder.clearContext();
但是,当站点重新加载时,它似乎没有任何效果,并且我永远不会收到另一个 HTTP 身份验证提示,除非重新启动浏览器(甚至清除缓存/cookie 没有帮助)。这是 applicationContext.xml 的相关部分
<security:http auto-config='true'>
<security:intercept-url pattern="/reports/**" access="ROLE_USER" />
<security:http-basic />
<security:logout logout-url="/reports/logout"
logout-success-url="/reports/Application.html" />
</security:http>
我尝试定义自定义 LogoutSuccessHandler
并执行 authentication.setAuthenticated(false);
但这也没有效果
我在这里缺少什么吗?非常感谢您的帮助
I retrofitted my GWT/GXT application with basic LDAP Authorization using basic HTTP authentication. It works well when I start new browser - I get the prompt and get authorized against corporate LDAP. My problem - I can't logout unless I close/reopen the browser. I can debug and see how SecurityContextLogoutHandler#logout
is called and the following code is executed
if (invalidateHttpSession) {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
}
SecurityContextHolder.clearContext();
However it seemingly has no effect as site is reloaded and I never get another HTTP auth prompt unless I restart the browser (even clearing the cache/cookies won't help). Here's relevant portion of applicationContext.xml
<security:http auto-config='true'>
<security:intercept-url pattern="/reports/**" access="ROLE_USER" />
<security:http-basic />
<security:logout logout-url="/reports/logout"
logout-success-url="/reports/Application.html" />
</security:http>
I tried to define custom LogoutSuccessHandler
and do authentication.setAuthenticated(false);
but that also has no effect
Anything here I'm missing here? Your help will be much appreciated
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
好的。在花费了太多时间之后,我想我已经有了答案。很简单 - 人们无法摆脱使用服务器端技术的基本 HTTP 身份验证。基本上,授权字符串在 HTTP 标头中进行 base-64 解码,当受保护的页面加载到浏览器时,安全令牌会重新填充,因此无论您在服务器上删除它的频率如何,每次调用该页面时它都会复活。我想可以在浏览器端玩一些聪明的技巧,但这将是脆弱且不可靠的。
对于我的情况,我将切换到基于表单的身份验证,无论如何,它可以更好地控制登录/注销过程。
我会继续接受我自己的答案,支持有人提出可接受的解决方案
OK. after spending way too much time with this I think I have the answer. It's simple - one cannot bail out of basic HTTP authentication using server-side technology. Basically authorization string is base-64 decoded in the HTTP header and when protected page is loaded to the browser the security token gets repopulated so no matter how often you erase it on the server it gets resurrected every time the page is called. I suppose it is possible to play some clever tricks on the browser side but that would be brittle and unreliable
For my case I will be switching to form-based authentication which gives much better control over login/logout process anyways.
I will hold on accepting my own answer in favor someone coming out with acceptable solution
波士顿基本上是正确的,你无法处理这个服务器端。然而,一些可用的黑客 。
简短的答案是将用户重定向到您希望他们登陆的 URL,但在其前面加上一个错误的用户名,后跟
@
。因此,作为一个丑陋的例子,理想情况下,您应该实现一个处理程序来为您执行此操作,但出于说明目的,我认为这可以理解这个概念。
Bostone is basically correct that you cannot handle this server-side. There is, however, a bit of a hack that's available.
The short answer is to redirect the user to the URL you want them to land on, but prefix it with a bad username followed by
@
. So as an ugly example,Ideally you'd implement a handler that would do this for you, but for illustration purposes, I think that gets the concept across.
嗯……奇怪。我没发现你的配置有什么问题。您确实不需要定义任何自定义注销处理程序,因为它应该由 Spring Security 处理。
尝试一下,不要定义您的
logout-url
,而是使用默认的注销链接:-然后,使用
/j_spring_security_logout
注销。这到底有用吗?
Uhm... strange. I don't see anything wrong with your configuration. You really don't need to define any custom logout handler because it should be handled by Spring Security.
Try this, instead of defining your
logout-url
, use the default logout link:-Then, use
/j_spring_security_logout
to logout.Does this work at all?
我坚信你是正确的。如果不在浏览器中执行,则无法使基本或摘要式身份验证无效。即使在那里,即使不是不可能,也将是极其困难的。坦率地说,我什至想不出一种方法可以在那里做到这一点(除了尝试关闭浏览器)。
正如您所指出的,问题在于,即使您使服务器端的所有内容无效,您也已经为浏览器提供了自动生成新的身份验证会话所需的一切。清除它的唯一方法是清除浏览器。即使重新启动服务器也不会清除浏览器创建新身份验证的能力,这很好地表明,如果不使基本或摘要身份验证合同无效,您将无法在服务器端完成此操作。
坦率地说,这似乎是浏览器中一个相当大的安全漏洞,因为在使用基本或摘要身份验证对站点进行身份验证后,您永远不应该让浏览器在开放访问服务器上运行。
表单身份验证可能是您最好的选择,因为除非您允许 Rememberme Cookie,否则您不会向浏览器提供有关如何恢复身份验证的信息。即使在那里,您也可以在注销时清除 cookie,这样会更容易。
I strongly believe that you are correct. You cannot invalidate a Basic or Digest authentication w/o doing it in the browser. Even there it is going to be extremely difficult if not impossible. Frankly I can't even think of a way to do it there (other than attempting to close the browser).
As you noted, the problem is that even though you invalidate everything on the server side, you have given the browser everything that it needs to automatically generate a new authentication session on its own. The only way to clear that is to clear the browser. Even restarting your server won't clear disable the ability of the browser to create a new authentication which is a pretty good indication that you're not going to be able to accomplish this on the server side without invalidating the Basic or Digest authentication contract.
Frankly this seems like a pretty substantial security hole in browsers in that you should never leave a browser running on an open access server after authenticating into a site with basic or digest authentication.
Form authentication may be your best bet because there you are not giving the browser information on how to resurrect an authentication unless you allow a rememberme cookie. Even there, you can clear the cookie on logout so that's easier.
我发现执行此操作的一种方法是返回 HTTP 401 响应。一些快速测试表明这适用于 Safari、Chrome 和 Chrome 的 macOS 版本。火狐。我使用的代码本质上与此相同:
技巧是您通常需要返回 401 标头两次 - 在第一次之后,浏览器将使用其缓存的凭据重试(发送“Authorization”标头,此时我们销毁用户的旧会话),第二个似乎清除它们并提示登录。
One way I've found to do this is to return HTTP 401 responses. Some quick testing shows this works in the macOS versions of Safari, Chrome & Firefox. The code I use is essentially equivalent to this:
The trick is that you usually need to return the 401 header twice - after the first one, the browser will retry with its cached credentials (sending the "Authorization" header, at which point we destroy the user's old session), the second one seems to clear them and prompts for a login.
只需将无效会话设置为“true”,看看它是否有效。
检查您的 web.xml 中是否存在此监听器:
如果上述方法不起作用,那么您可以尝试以下解决方案。
我认为问题出在您的以下行,
上面的行意味着您将访问权限 ROLE_USER 添加到了“/reports/**”链接。
但注销后,您会为注销成功提供相同的网址。那么它将如何运作呢?
更改注销成功页面的位置,或者您可以在 http 标记中添加以下行。
just set invalidate session to 'true' and see does it works.
check if this listner is there in your web.xml:
If above things do not work then you can try following solution.
I think problem is with your following line,
Above line means that you added access ROLE_USER to yout '/reports/**' link.
But after logout you are giving same url for logout success. then how it will work?
Either change location of your logout success page or you can add followin line in http tag.