Spring Security 4 Logout Example

This post shows you how to programatically logout a user in Spring Security. This works well with browser back button too.

SpringSecurityCustomLogoutExample_img4


Generally, In your views, you should be providing a simple logout link to logout a user, something like shown below:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
	<title>Admin page</title>
</head>
<body>
	Dear <strong>${user}</strong>, Welcome to Admin Page.
	<a href="<c:url value="/logout" />">Logout</a>
</body>
</html>

Nothing fancy about it. Now , We just need to map this /logout link in our controller. Create a new method like shown below:

	@RequestMapping(value="/logout", method = RequestMethod.GET)
	public String logoutPage (HttpServletRequest request, HttpServletResponse response) {
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();
		if (auth != null){    
			new SecurityContextLogoutHandler().logout(request, response, auth);
		}
		return "redirect:/login?logout";//You can redirect wherever you want, but generally it's a good practice to show login screen again.
	}

Here firstly we identified if user was authenticated before using SecurityContextHolder.getContext().getAuthentication(). If he/she was, then we called SecurityContextLogoutHandler().logout(request, response, auth) to logout user properly.

This logout call performs following:

  • Invalidates HTTP Session ,then unbinds any objects bound to it.
  • Removes the Authentication from the SecurityContext to prevent issues with concurrent requests.
  • Explicitly clears the context value from the current thread.

That’s it. You don’t need anything else anywhere in your application to handle logout. Notice that you don’t even need to do anything special in your spring configuration(xml or annotation based), shown below just for information:

package com.websystique.springsecurity.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	
	@Autowired
	public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("USER");
		auth.inMemoryAuthentication().withUser("admin").password("root123").roles("ADMIN");
		auth.inMemoryAuthentication().withUser("dba").password("root123").roles("ADMIN","DBA");
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
	  
	  http.authorizeRequests()
	  	.antMatchers("/", "/home").permitAll()
	  	.antMatchers("/admin/**").access("hasRole('ADMIN')")
	  	.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
	  	.and().formLogin().loginPage("/login")
	  	.usernameParameter("ssoId").passwordParameter("password")
	  	.and().exceptionHandling().accessDeniedPage("/Access_Denied");
	}
}

There is no special logout handling mentioned in above configuration.

Above security configuration in XML configuration format would be:

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
    http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">
     
    <http auto-config="true" >
        <intercept-url pattern="/" access="hasRole('USER')" />
        <intercept-url pattern="/home" access="hasRole('USER')" />
        <intercept-url pattern="/admin**" access="hasRole('ADMIN')" />
        <intercept-url pattern="/dba**" access="hasRole('ADMIN') and hasRole('DBA')" />
        <form-login  login-page="/login" 
                     username-parameter="ssoId" 
                     password-parameter="password" 
                     authentication-failure-url="/Access_Denied" />
    </http>
 
    <authentication-manager >
        <authentication-provider>
            <user-service>
                <user name="bill"  password="abc123"  authorities="ROLE_USER" />
                <user name="admin" password="root123" authorities="ROLE_ADMIN" />
                <user name="dba"   password="root123" authorities="ROLE_ADMIN,ROLE_DBA" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
    
</beans:beans>

Rest of application code is same as mentioned in every post in this series. This Post (and actually every post in this series) shows this logout in action.

Deploy & Run

Download complete code of this project using download button shown at the bottom of this post. Build and deploy it on Servlet 3.0 container(Tomcat7/8).

Open your browser, go to http://localhost:8080/SpringSecurityCustomLogoutExample/, home page will be shown

SpringSecurityCustomLogoutExample_img1

Now go to http://localhost:8080/SpringSecurityCustomLogoutExample/admin, you will be prompted for login

SpringSecurityCustomLogoutExample_img2

provide credentials, submit, you will see admin page.

SpringSecurityCustomLogoutExample_img3

click on logout, you will be taken to login page.

SpringSecurityCustomLogoutExample_img4

click on browser back button, you will remain at login screen.

SpringSecurityCustomLogoutExample_img5

That’s it. Next post shows you how to show/hide parts of jsp/view based on logged-in user’s roles, using Spring Security tags.

Download Source Code



References

If you like tutorials on this site, why not take a step further and connect me on Facebook , Google Plus & Twitter as well? I would love to hear your thoughts on these articles, it will help me improve further our learning process.

If you appreciate the effort I have put in this learning site, help me improve the visibility of this site towards global audience by sharing and linking this site from within and beyond your network. You & your friends can always link my site from your site on www.websystique.com, and share the learning.

After all, we are here to learn together, aren’t we?

  • Pingback: Spring Security 4 Custom Login Form Annotation+XML Example - WebSystique()

  • Muhammed Abdul

    Hi Thank you for the great tutorials, these are really helpful.

    I have downloaded the code for this particular example , then did the following steps
    1. Ran mvn dependency:copy-dependencies in the project folder
    2. Imported the project into eclipse
    3. Ran Maven update
    4. Converted project to dynamic web project using the project facets and specifying the webcontent folder as src/main/webapp
    5. Ran the application on tomcat 7, jdk 1.7.0_91, but the application gave 404 error when loading the home page.

    Could you please let me know how do i run the downloaded code?

    • websystique

      Hi Abdul, probably your tomcat setup is not configured properly. Please have a look on Setup Tomcat With Eclipse, following the steps mentioned here should solve your issue.

      • Muhammed Abdul

        Thank you for your swift response. As of now, i am using mvn clean install and then deploying the war manually on to the tomcat server using the tomcat manager gui.

        My eclipse embedded tomcat setup is correct as i am able to run other web apps using eclipse.

        I actually never used maven, but can you tell me after i download, how do i import this to eclipse as a WEB APP and then run it using eclipse, run as -> run on server… .

        Any help/pointers would be really helpful.

        Thank you in advance. :)

  • acidnbass

    This should be updated to include functionality to remove rememberMe cookies that will cause the user to be re-authenticated regardless of the session-invalidating/SecurityContextHolder emptying process that the `SecurityContextLogoutHandler.logout(…)` call induces; see http://stackoverflow.com/questions/5727380/how-to-manually-log-out-a-user-with-spring-security :

    you need to add a call to CookieClearingLogoutHandler.logout(…) with a cookieClearingLogoutHandler initialized with AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY

    • websystique

      Hi,
      Thanks for pointing it out. You are absolutely right. Even if we are not discussing about cookie in this particular post, we should include the cookie removal logic to perform a clean logout. I will update the post. Thanks again.