如何使用Spring Security手动注销用户?

75
也许答案很简单:如何在Spring Security中手动注销当前登录的用户?只需要调用以下方法即可:
SecurityContextHolder.getContext().getAuthentication().setAuthenticated(false); 

?


非常感谢你们的回答,我会去查看它们。 - Erik
11个回答

81

我很难确定你的代码是否足够。然而,标准的Spring Security登出实现是不同的。如果你查看SecurityContextLogoutHandler,你会发现他们做了以下操作:

SecurityContextHolder.clearContext();

此外,它们可以选择使HttpSession无效:
if (invalidateHttpSession) {
    HttpSession session = request.getSession(false);
    if (session != null) {
        session.invalidate();
    }
}

您可以通过查看Spring Security中有关注销的其他问题在某些其他有关Spring Security注销的问题中以及查看org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler的源代码来获取更多信息。


3
如果已经设置了记住登录cookie,您也会希望删除它。 - sourcedelica

45

在Servlet 3.0容器中,Spring注销功能与servlet集成,您只需在HttpServletRequest上调用logout()即可。仍需要编写有效的响应内容。

根据文档 (Spring 3.2):

可以使用HttpServletRequest.logout()方法来注销当前用户。

通常这意味着SecurityContextHolder将被清除,HttpSession将被无效,任何"记住我"身份验证将被清除等。


在Spring 3.1.2 / Grails 2.2.0中,Tomcat 7的org.apache.catalina.connector.Request#logout实现会导致NPE错误。使用clearContext()不会出现这种错误。 - Pavel Vlasov
@PavelVlasov 我认为这是Spring配置中的一些错误,请阅读有关SecurityContextHolder的内容。 - Piotr Müller
5
在执行 request.logout() 后,我仍然可以在 SecurityContextHolder.getContext().getAuthentication() 中找到已授权的用户。 - Grigory Kislin

28

我在LogoutFilter中使用相同的代码,重复利用LogoutHandlers,如下所示:

public static void myLogoff(HttpServletRequest request, HttpServletResponse response) {
    CookieClearingLogoutHandler cookieClearingLogoutHandler = new CookieClearingLogoutHandler(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY);
    SecurityContextLogoutHandler securityContextLogoutHandler = new SecurityContextLogoutHandler();
    cookieClearingLogoutHandler.logout(request, response, null);
    securityContextLogoutHandler.logout(request, response, null);
}

2
由于CookieClearingLogoutHandler,+1,否则如果用户有rememberme cookie,则可以再次登录。请注意,此类需要Spring 3.1。 - redochka
这是正确的工作解决方案,如果你有自定义的RememberMe处理。 - David H

10

你也可以使用SessionRegistry

sessionRegistry.getSessionInformation(sessionId).expireNow();
如果您想强制注销用户的所有会话,则使用 getAllSessions 方法并调用每个会话信息的 expireNow 方法。 编辑
这需要ConcurrentSessionFilter(或链中的任何其他过滤器),它检查SessionInformation并调用所有注销处理程序,然后进行重定向。

10

在Web应用程序中注销用户时,您也可以将用户重定向到注销页面。然后LogoutFilter会为您完成所有工作。

注销页面的URL在安全配置中设置:

<sec:http ...>
  ...
  <sec:logout logout-url="/logout" logout-success-url="/login?logout_successful=1" />
  ...
</sec:http>

1
这对我没用。它并不像你所建议的那么简单。还有更多的配置细节吗? - djangofan
这应该是可行的,不需要其他配置。你只需将用户重定向到类似于“http://example.com/yourctx/logout”的URL即可。 - James
我已经让它工作了,但我不得不重新启动Tomcat才能让它正常工作。 - djangofan

4

Right Oledzki,我在我的控制器中使用以下代码示例来注销并重定向用户到Spring Security 4.2.3中的登录页面:

SecurityContextHolder.clearContext();

if(session != null)
    session.invalidate();

return "redirect:/login";

4

new SecurityContextLogoutHandler().logout(request, null, null);

的意思是创建一个安全上下文注销处理器,并使用它来注销当前用户的登录状态。在调用该方法时,需要传递请求对象和两个空参数。

3
只需按照以下方式操作(注释为“与您相关的”部分):
    Authentication auth = SecurityContextHolder.getContext().getAuthentication(); // concern you

    User currUser = userService.getUserById(auth.getName()); // some of DAO or Service...

    SecurityContextLogoutHandler ctxLogOut = new SecurityContextLogoutHandler(); // concern you

    if( currUser == null ){
        ctxLogOut.logout(request, response, auth); // concern you
    }

2
最近我们需要使用Spring-security 3.0.5实现注销功能。虽然这个问题已经在上面得到了解答,但我将发布完整的代码,这肯定会帮助像我这样的新手用户 :)

在Spring-security.xml中进行配置

 <http auto-config="false" lowercase-comparisons="false" use-expressions="true">
     <custom-filter position="LOGOUT_FILTER" ref="logoutFilter" />
 </http>

<beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
        <beans:constructor-arg name="logoutSuccessHandler" ref="xxxLogoutSuccessHandler" />
    <beans:constructor-arg name="handlers">
        <beans:list>
            <beans:ref bean="securityContextLogoutHandler"/>
            <beans:ref bean="xxxLogoutHandler"/>
        </beans:list>
    </beans:constructor-arg>
    <beans:property name="filterProcessesUrl" value="/logout"/>
</beans:bean>
<beans:bean id="XXXLogoutSuccessHandler" class="com.tms.dis.sso.XXXLogoutSuccessHandler"/>
<beans:bean id="securityContextLogoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
    <beans:property name="invalidateHttpSession" value="true"/>
</beans:bean>
<beans:bean id="XXXLogoutHandler" class="com.tms.dis.sso.XXXLogoutHandler"/>

我创建了两个自定义类:

  1. XXXLogoutHandler 实现 org.springframework.security.web.authentication.logout.LogoutHandler,并覆盖 logout() 方法。
  2. XXXLogoutSuccessHandler 实现 org.springframework.security.web.authentication.logout.LogoutSuccessHandler,并覆盖 onLogoutSuccess() 方法。在 XXXLogoutSuccessHandler.onLogoutSuccess() 方法中调用 redirectStrategy.sendRedirect() 方法,将用户注销到特定的 targetURL。
  3. org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler 完成了使用户会话失效的任务。

希望这能有所帮助并为初学者提供正确的方向。

注意:故意没有发布自定义实现的代码。


1

非常简单,要手动注销Spring Security,只需利用Servlet请求本身即可。 例如:如下所示:

@PostMapping("/manualLogout")
public String customLogut(Model models, HttpServletRequest request) throws ServletException
{
    request.logout();
    return "redirect:/";
}

感谢您的问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接