我使用基本的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);
,但这也没有效果
我在这里缺少什么?非常感谢您的帮助
答案 0 :(得分:25)
行。花了太多时间后,我觉得我有答案。这很简单 - 使用服务器端技术无法摆脱基本的HTTP身份验证。基本上,授权字符串在HTTP标头中进行base-64解码,当受保护的页面加载到浏览器时,安全令牌会重新填充,因此无论您在服务器上擦除它的频率如何,每次调用页面时它都会被复活。我想可以在浏览器端发挥一些巧妙的技巧,但那会很脆弱且不可靠
对于我的情况,我将切换到基于表单的身份验证,无论如何都可以更好地控制登录/注销过程。
我会坚持接受我自己的回答,支持有人提出可接受的解决方案
答案 1 :(得分:4)
Bostone基本上是正确的,你无法处理这个服务器端。但是,有a bit of a hack that's available。
简短的回答是将用户重定向到您希望他们登陆的网址,但在其前面加上错误的用户名,后跟@
。所以作为一个丑陋的例子,
<security:logout logout-url="/reports/logout"
logout-success-url="http://BADNAME@localhost/reports/Application.html" />
理想情况下,您将实现一个可以为您执行此操作的处理程序,但出于说明目的,我认为可以实现此概念。
答案 2 :(得分:3)
尝试此操作,而不是定义logout-url
,请使用默认的注销链接: -
...
<security:logout logout-success-url="/reports/Application.html" />
...
然后,使用/j_spring_security_logout
注销。
这有用吗?
答案 3 :(得分:0)
<logout invalidate-session="true" logout-url="/reports/logout"
logout-success-url="/reports/Application.html" />
将invalidate session设置为'true',看看它是否有效。
检查web.xml中是否存在此列表:
<!-- Security: to listen session requests -->
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
如果以上情况不起作用,那么您可以尝试以下解决方案。 我认为问题出在你的下一行,
<security:intercept-url pattern="/reports/**" access="ROLE_USER" />
以上行表示您已将访问权限ROLE_USER添加到yout'/ reports / **'链接。 但是在注销后,您将为注销成功提供相同的URL。那它将如何运作? 您可以更改注销成功页面的位置,也可以在http标记中添加以下行。
<intercept-url pattern="/reports/Application.html" filters="none" />
答案 4 :(得分:0)
我坚信你是对的。您无法在浏览器中使用Basic或Digest身份验证无效。即使在那里,即使不是不可能,也会非常困难。坦率地说,我甚至想不出办法在那里做到(除了试图关闭浏览器)。
正如您所指出的,问题是即使您使服务器端的所有内容无效,您也已经为浏览器提供了自动生成新身份验证会话所需的一切。清除它的唯一方法是清除浏览器。即使重新启动服务器也不会清除禁用浏览器创建新身份验证的能力,这很好地表明您无法在服务器端完成此操作而不会使Basic或Digest身份验证协议失效。
坦率地说,这似乎是浏览器中一个非常重要的安全漏洞,因为在使用基本身份验证或摘要身份验证进行身份验证后,您绝不应让浏览器在开放式访问服务器上运行。
表单身份验证可能是您最好的选择,因为除非您允许记住cookie,否则您不会向浏览器提供有关如何恢复身份验证的信息。即使在那里,您也可以在注销时清除cookie,这样更容易。
答案 5 :(得分:0)
我发现这样做的一种方法是返回HTTP 401响应。一些快速测试表明这适用于Safari,Chrome和Mac的macOS版本。 Firefox浏览器。我使用的代码基本上等同于:
@RequestMapping(value="/logout",method=RequestMethod.POST)
public void logout(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
session.setAttribute(LOGOUT_SESSION_KEY, true);
response.setStatus(303);
response.addHeader("Location", URL_OF_APPLICATION_HOME_PAGE);
}
@RequestMapping("/")
public void home(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
if (Boolean.TRUE.equals(session.getAttribute(LOGOUT_SESSION_KEY))) {
if (request.getHeader("Authorization") != null) {
session.invalidate();
}
response.setStatus(401);
response.addHeader("WWW-Authenticate", "Basic realm=\"" + HTTP_BASIC_REALM + "\"");
return;
}
/* Generate home page */
}
诀窍是你通常需要两次返回401标题 - 在第一个之后,浏览器将使用其缓存的凭据重试(发送&#34;授权&#34;标头,此时我们会销毁用户& #39;旧会话),第二个似乎清除它们并提示登录。