74

Probably the answer is simple: How can I manually logout the currently logged in user in spring security? Is it sufficient to call:

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

?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Erik
  • 11,944
  • 18
  • 87
  • 126

11 Answers11

79

It's hard for me to say for sure if your code is enough. However standard Spring-security's implementation of logging out is different. If you took a look at SecurityContextLogoutHandler you would see they do:

SecurityContextHolder.clearContext();

Moreover they optionally invalidate the HttpSession:

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

You may find more information in some other question about logging out in Spring Security and by looking at the source code of org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler.

Stefa168
  • 35
  • 2
  • 9
Grzegorz Oledzki
  • 23,614
  • 16
  • 68
  • 106
44

In Servlet 3.0 container Spring logout functionality is integrated with servlet and you just invoke logout() on your HttpServletRequest. Still need to write valid response content.

According to documentation (Spring 3.2):

The HttpServletRequest.logout() method can be used to log the current user out.

Typically this means that the SecurityContextHolder will be cleared out, the HttpSession will be invalidated, any "Remember Me" authentication will be cleaned up, etc.

Piotr Müller
  • 5,323
  • 5
  • 55
  • 82
  • Having an NPE at Tomcat 7's `org.apache.catalina.connector.Request#logout` implementation for Spring 3.1.2 / Grails 2.2.0. No such error with `clearContext()`. – Pavel Vlasov Oct 22 '14 at 05:15
  • @PavelVlasov I believe it's a some mistake in spring configuration, read about SecurityContextHolder. – Piotr Müller Jun 19 '15 at 09:13
  • 5
    After `request.logout()` I still has authorized user in `SecurityContextHolder.getContext().getAuthentication()` – Grigory Kislin Oct 25 '17 at 15:08
28

I use the same code in LogoutFilter, reusing the LogoutHandlers as following:

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);
}
gibaholms
  • 306
  • 3
  • 4
  • 2
    +1 because of CookieClearingLogoutHandler otherwise user can log in again if she had the rememberme cookie. Note that this class requires spring 3.1 – redochka May 20 '14 at 10:22
  • This is the correct working solution if you have custom RememberMe handling – David H Jul 11 '23 at 15:14
10

To log out a user in a web application you can also redirect him to the logout page. The LogoutFilter is then doing all the work for you.

The url of the logout page is set in the security configuration:

<sec:http ...>
  ...
  <sec:logout logout-url="/logout" logout-success-url="/login?logout_successful=1" />
  ...
</sec:http>
James
  • 11,654
  • 6
  • 52
  • 81
  • 1
    This didnt work for me. Its not as simple as you suggest. Any more configuration details? – djangofan Nov 30 '12 at 04:14
  • There should be no other configuration necessary for this to work. You simply redirect the user to an URL like "http://example.com/yourctx/logout". – James Nov 30 '12 at 07:55
  • I got it working but i had to restart Tomcat for it to start working. – djangofan Nov 30 '12 at 17:33
10

You can also use SessionRegistry as:

sessionRegistry.getSessionInformation(sessionId).expireNow();

If you want to force logout in all sessions of a user then use getAllSessions method and call expireNow of each session information.

Edit
This requires ConcurrentSessionFilter (or any other filter in the chain), that checks SessionInformation and calls all logout handlers and then do redirect.

Ritesh
  • 7,472
  • 2
  • 39
  • 43
4

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

Tiago
  • 691
  • 7
  • 12
4

Right Oledzki, I am using the following for example inside my controller to logout and redirect the user to the login page in spring security 4.2.3

SecurityContextHolder.clearContext();

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

return "redirect:/login";
Hany Sakr
  • 2,591
  • 28
  • 27
3

Simply do like this (the ones commented by "concern you") :

    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
    }
loulou
  • 331
  • 1
  • 5
  • 20
2

Recently we had to implement logout functionality using Spring-security 3.0.5. Although this question is already answered above, I will post the complete code which would definitely help novice user like me :)

Configuration in 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"/>

Here i have created two custom classes

  1. XXXLogoutHandler which will implement org.springframework.security.web.authentication.logout.LogoutHandler and will override the logout() method.
  2. XXXLogoutSuccessHandler which will implement org.springframework.security.web.authentication.logout.LogoutSuccessHanlder and will override onLoguoutSuccess() method. Within the XXXLogoutSuccessHandler.onLogoutSuccess() method call the redirectStrategy.sendRedirect() method which logout the user to the particular targetURL.
  3. org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler does the task of invalidating the user session.

Hope this would help and give the correct direction to the starter

Note: Intentionally have not posted code for custom implementation.

Nayan
  • 578
  • 7
  • 13
1

Very simple, to logout of spring security manually, just make use of the Servlet request itself. i.e. As below :

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

Thanks for the question.

0

In you controller >> signOut method do not return "/logout" but redirect to the /logout method in the spring security context: return "redirect:/logout";

overheated
  • 310
  • 4
  • 11