Spring安全 - 无法注销

时间:2011-02-17 00:46:36

标签: spring-security basic-authentication logout

我使用基本的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);,但这也没有效果

我在这里缺少什么?非常感谢您的帮助

6 个答案:

答案 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)

嗯......很奇怪。我没有看到您的配置有任何问题。您真的不需要定义任何自定义注销处理程序,因为它应该由Spring Security处理。

尝试此操作,而不是定义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;旧会话),第二个似乎清除它们并提示登录。