【问题标题】:How to manually log out a user with spring security?如何使用弹簧安全手动注销用户?
【发布时间】:2011-08-09 07:14:06
【问题描述】:

可能答案很简单:如何在 spring security 中手动注销当前登录的用户? 打电话就够了:

SecurityContextHolder.getContext().getAuthentication().setAuthenticated(false); 

?

【问题讨论】:

  • 非常感谢您的回答,我会检查出来。

标签: spring spring-security logout


【解决方案1】:

我很难确定您的代码是否足够。但是标准 Spring-security 的注销实现是不同的。如果您查看SecurityContextLogoutHandler,您会发现他们这样做了:

    SecurityContextHolder.clearContext();

此外,它们还可以选择使 HttpSession 无效:

    if (invalidateHttpSession) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.invalidate();
        }
    }

您可以通过in some other question about logging out in Spring Securitythe source code of org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler 找到更多信息。

【讨论】:

  • 如果设置了 rememberme cookie,您还需要删除它。
【解决方案2】:

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

根据documentation(春季 3.2):

HttpServletRequest.logout() 方法可用于注销当前用户。

通常这意味着 SecurityContextHolder 将被清除 出,HttpSession 将失效,任何“记住我” 身份验证将被清理等。

【讨论】:

  • 在 Spring 3.1.2 / Grails 2.2.0 的 Tomcat 7 的 org.apache.catalina.connector.Request#logout 实现中有一个 NPE。 clearContext() 没有这样的错误。
  • @PavelVlasov 我认为这是 spring 配置中的一个错误,请阅读 SecurityContextHolder。
  • request.logout() 之后我在SecurityContextHolder.getContext().getAuthentication() 中还有授权用户
【解决方案3】:

我在 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);
}

【讨论】:

  • +1 因为 CookieClearingLogoutHandler 否则如果她有 rememberme cookie,用户可以再次登录。注意这个类需要spring 3.1
【解决方案4】:

您也可以将SessionRegistry 用作:

sessionRegistry.getSessionInformation(sessionId).expireNow();

如果你想在一个用户的所有会话中强制注销然后使用getAllSessions方法并调用每个会话信息的expireNow

编辑
这需要ConcurrentSessionFilter(或链中的任何其他过滤器),它检查 SessionInformation 并调用所有注销处理程序,然后进行重定向。

【讨论】:

    【解决方案5】:

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

    退出页面的url在安全配置中设置:

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

    【讨论】:

    • 这对我不起作用。它不像你建议的那么简单。还有更多配置细节吗?
    • 应该不需要其他配置才能使其工作。您只需将用户重定向到“example.com/yourctx/logout”之类的 URL。
    • 我让它工作了,但我必须重新启动 Tomcat 才能开始工作。
    【解决方案6】:

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

    【讨论】:

      【解决方案7】:

      就这么干吧(那些被“关心你”的评论):

          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
          }
      

      【讨论】:

        【解决方案8】:

        最近我们不得不使用 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.LogoutSuccessHanlder 并将覆盖 onLoguoutSuccess() 方法。在 XXXLogoutSuccessHandler.onLogoutSuccess() 方法中调用 redirectStrategy.sendRedirect() 方法将用户注销到特定的 targetURL。
        3. org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler 执行使用户会话无效的任务。

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

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

        【讨论】:

          【解决方案9】:

          Right Oledzki,我在我的控制器中使用以下示例来注销并将用户重定向到 spring security 4.2.3 中的登录页面

          SecurityContextHolder.clearContext();
          
          if(session != null)
              session.invalidate();
          
          return "redirect:/login";
          

          【讨论】:

            【解决方案10】:

            在你的控制器>>signOut方法 不返回“/logout”,而是重定向到spring安全上下文中的/logout方法:return "redirect:/logout";

            【讨论】:

              【解决方案11】:

              很简单,手动注销spring security, 只需使用 Servlet 请求本身。 即如下:

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

              感谢您的提问。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-08-04
                • 2012-10-05
                • 2015-03-19
                • 2018-09-08
                • 2016-11-22
                • 2013-12-14
                相关资源
                最近更新 更多