Spring security - 无法注销
Posted
技术标签:
【中文标题】Spring security - 无法注销【英文标题】:Spring security - unable to logout 【发布时间】:2011-06-28 18:42:38 【问题描述】:我使用基本 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);
但这也没有效果
这里有什么我想念的吗?非常感谢您的帮助
【问题讨论】:
【参考方案1】:好的。在花了太多时间处理这个问题之后,我想我有了答案。这很简单——人们无法摆脱使用服务器端技术的基本 HTTP 身份验证。基本上授权字符串在 HTTP 标头中进行 base-64 解码,当受保护的页面加载到浏览器时,安全令牌会重新填充,因此无论您多久在服务器上删除它,每次调用页面时它都会复活。我想可以在浏览器端玩一些巧妙的技巧,但这会很脆弱且不可靠
就我而言,我将切换到基于表单的身份验证,这样可以更好地控制登录/注销过程。
我会坚持接受我自己的答案,以支持提出可接受解决方案的人
【讨论】:
我发现了同样的事情(经过很长时间),但很难相信没有什么可以做的。【参考方案2】:Bostone 基本上是正确的,您无法处理此服务器端。不过有a bit of a hack that's available。
简短的回答是将用户重定向到您希望他们登陆的 URL,但在其前面加上一个错误的用户名,后跟 @
。举个丑陋的例子,
<security:logout logout-url="/reports/logout"
logout-success-url="http://BADNAME@localhost/reports/Application.html" />
理想情况下,您应该实现一个可以为您执行此操作的处理程序,但出于说明目的,我认为这可以理解这个概念。
【讨论】:
不幸的是,这在最近的浏览器中似乎不再可靠地工作,可能是由于在网络钓鱼电子邮件中使用了那种 URL。 Chrome 会简单地忽略用户名,Firefox 会弹出一个警告,提示您正在尝试登录不需要登录的站点,而 Safari 会显示一个大的红色网络钓鱼警报。【参考方案3】:嗯……奇怪。我看不出你的配置有什么问题。您真的不需要定义任何自定义注销处理程序,因为它应该由 Spring Security 处理。
试试这个,而不是定义你的logout-url
,使用默认的注销链接:-
...
<security:logout logout-success-url="/reports/Application.html" />
...
然后,使用/j_spring_security_logout
注销。
这行得通吗?
【讨论】:
毫不奇怪,这具有相同的效果。正如我所说 - 它通过 LogoutHandler 逻辑只是它似乎什么都不做 我的接线没有问题。事实是 - 基本 HTTP 不支持注销【参考方案4】:我发现这样做的一种方法是返回 HTTP 401 响应。一些快速测试表明这适用于 macOS 版本的 Safari、Chrome 和 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 标头两次 - 在第一次之后,浏览器将使用其缓存的凭据重试(发送“授权”标头,此时我们会销毁用户的旧会话),第二个似乎清除了它们并提示登录。
【讨论】:
【参考方案5】:<logout invalidate-session="true" logout-url="/reports/logout"
logout-success-url="/reports/Application.html" />
只需将无效会话设置为“真”,看看它是否有效。
检查你的 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 添加到您的“/reports/**”链接。 但是在注销后,您将提供相同的 url 以便注销成功。那么它将如何工作? 更改注销成功页面的位置,或者您可以在 http 标签中添加后续行。
<intercept-url pattern="/reports/Application.html" filters="none" />
【讨论】:
抱歉,您的建议均无效。默认情况下,invalidate-session=true,我确实添加了侦听器和注销页面。但是我认为注销页面是无关紧要的(默认情况下是 / ),因为即使它丢失了,因为我在注销后立即使用基本的 HTTP 登录,我应该被登录提示击中,而这正是没有发生的事情。我可以逐步执行它执行的注销代码,但这没有任何区别。除非我杀死浏览器,否则我将保持登录状态 我不知道谁给了这个解决方案一个积极的计数,但它基本上是不正确的。查看我自己的答案【参考方案6】:我坚信你是正确的。您不能在浏览器中使基本或摘要身份验证无效。即使在那里,如果不是不可能的话,也将是极其困难的。坦率地说,我什至想不出办法在那里(除了尝试关闭浏览器)。
正如您所指出的,问题在于即使您使服务器端的所有内容都无效,您也已经为浏览器提供了它自己自动生成新的身份验证会话所需的一切。清除它的唯一方法是清除浏览器。即使重新启动您的服务器也不会清除禁用浏览器创建新身份验证的能力,这很好地表明您将无法在服务器端完成此操作而不使基本或摘要身份验证合同无效。
坦率地说,这似乎是浏览器中的一个相当大的安全漏洞,因为在使用基本或摘要式身份验证对站点进行身份验证后,您永远不应让浏览器在开放访问服务器上运行。
表单身份验证可能是您最好的选择,因为除非您允许记忆 cookie,否则您不会向浏览器提供有关如何恢复身份验证的信息。即使在那里,您也可以在注销时清除 cookie,这样更容易。
【讨论】:
以上是关于Spring security - 无法注销的主要内容,如果未能解决你的问题,请参考以下文章
带有 LDAP 注销的 Spring Security 无法删除会话