Spring Security: Custom LogoutHandler
Let's say you've got your Spring Security 3 application working. You can login. You've got a RememberMeServices set up, so users don't have to login each time they visit your site. But you're having trouble getting the logout functionality to work, or maybe you just need to define some custom functionality to be called when the user logs out. What you need is a custom LogoutHandler.
If you have a <logout> element defined in your <http> namespace element, go ahead and get rid of that since we will be manually configuring what <logout> does for you.
Configure a LogoutFilter
First, let's configure our LogoutFilter:
<beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"> <beans:constructor-arg index="0" value="/login" /> <beans:constructor-arg index="1"> <beans:list> <beans:ref bean="rememberMeServices" /> <beans:bean id="securityContextLogoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" /> </beans:list> </beans:constructor-arg> <beans:property name="filterProcessesUrl" value="/logout" /> </beans:bean>
One of the great things about Spring Security is that it provides lots of classes right out of the box that we can simply configure. No custom coding is necessary (not now, at least).
As you can see, we're just defining a LogoutFilter and setting two constructor arguments, and one property. The first argument is the URL to redirect to after logging the user out. Use whatever you want here; for our example, I'm redirecting the user to the login page.
The second argument is a variable-length list of LogoutHandler implementations, i.e. classes that implement the LogoutHandler interface. I have a RememberMeServices, so I have that included. I also want my user's session invalidated, so I've also included a SecurityContextLogoutHandler. According to the Spring documentation, it is recommended to have your RememberMeServices called first and then the SecurityContextLogoutHandler. The RememberMeServices takes care of removing the remember me stuff (cookie, database entries, etc.), and the SecurityContextLogoutHandler handles invalidating the user's session.
The property we are setting is the filterProcessesUrl which tells Spring Security on which URL to "monitor". I've set it to /logout, so when a user hits that URL the LogoutFilter will be called.
The next thing to do is to tell Spring Security that we want our LogoutFilter included in the filter chain. There are two ways to do this. The first way is if you are using a <http> element, in which case you will need to add <custom-filter> like this:
<http use-expressions="true" auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint"> ... <custom-filter position="LOGOUT_FILTER" ref="logoutFilter" /> </http>
If you are not using the <http> element and instead are just using standard beans, you'll need to add the <custom-filter> to the LogoutFilter bean configuration:
<beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"> <beans:constructor-arg index="0" value="/login" /> <beans:constructor-arg index="1"> <beans:list> <beans:ref bean="rememberMeServices" /> <beans:bean id="securityContextLogoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" /> </beans:list> </beans:constructor-arg> <beans:property name="filterProcessesUrl" value="/logout" /> <custom-filter position="LOGOUT_FILTER"/> </beans:bean>
So now that we've got a LogoutFilter configured, we should be able to click a logout link and have the user's rememberMe cookie removed along with any corresponding database records, as well as have the user's session invalidated.
Custom LogoutHandler
That's all good and well, you say, but I need some custom functionality to be invoked when the user logs out. Luckily, that is the easiest part of this entire post.
First, create a LogoutHandler implementation:
public class MyLogoutHandler implements LogoutHandler { public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { // Do whatever you want here. } }
The next thing to do is add the custom LogoutHandler to our LogoutFilter we defined earlier:
<beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"> <beans:constructor-arg index="0" value="/account/login" /> <beans:constructor-arg index="1"> <beans:list> <beans:ref bean="rememberMeServices" /> <beans:bean id="securityContextLogoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" /> <beans:bean id="myLogoutHandler" class="com.awnry.springexample.MyLogoutHandler" /> </beans:list> </beans:constructor-arg> <beans:property name="filterProcessesUrl" value="/account/logout" /> </beans:bean>
And there you have it. The MyLogoutHandler.logout() method will now be invoked as part of the LogoutFilter chain, allowing you to do any miscellaneous cleanup.
















