Spring Security provides comprehensive support for adding custom handlers for logout/login. The default logout simply logs the user out and goes to the login page. What if the application needs to determine the user’s role and redirect to a separate screen? For example, for an admin, a custom logout screen. What if the user is automatically logged out after 10 mins of user inactivity? You don’t want the user to see a login screen without any message on it. That’s bad.
Here’s an example demonstrating a custom logout handler using Spring 3 security module. The code has some incompatibility issues with Spring 2 as Spring 3 Security is not 100% backward compatibility.
Sample User
public class User extends org.springframework.security.core.userdetails.User {
// Stuff
}
Custom Filter Handler
import java.io.IOException;
import javax.annotation.PostConstruct;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import xxx.model.User;
public class LogoutFilterWrapper
implements Filter {
private String logoutSuccessfulUrl;
private String logoutSuccessfulUrlAdmin;
private String logoutSuccessfulInactivityUrl;
private LogoutFilter filter;
@PostConstruct
protected void initialize() {
final SecurityContextLogoutHandler context = new SecurityContextLogoutHandler();
context.setInvalidateHttpSession( true );
this.filter =
new LogoutFilter( new CustomLogoutSuccessHandler(), new LogoutHandler[] { context } );
}
public void setLogoutSuccessfulUrl(
String inUrl ) {
this.logoutSuccessfulUrl = inUrl;
}
public void setLogoutSuccessfulUrlAdmin(
String inUrl ) {
this.logoutSuccessfulUrlAdmin = inUrl;
}
public void setLogoutSuccessfulUrlInactivity(
String inUrl ) {
this.logoutSuccessfulInactivityUrl = inUrl;
}
public final void init(
FilterConfig inFilterConfig )
throws ServletException {
this.filter.init( inFilterConfig );
}
public final void destroy() {
this.filter.destroy();
}
public final void doFilter(
ServletRequest inRequest,
ServletResponse inResponse,
FilterChain inChain )
throws IOException, ServletException {
this.filter.doFilter( inRequest, inResponse, inChain );
}
/**
* Success Handler
*/
private class CustomLogoutSuccessHandler
implements LogoutSuccessHandler {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
public void onLogoutSuccess(
HttpServletRequest request,
HttpServletResponse response,
Authentication authentication )
throws IOException, ServletException {
String targetUrl = "";
User principal = null;
if ( authentication != null ) {
if ( !(authentication.getPrincipal() instanceof User) ) {
throw new IllegalArgumentException( "Invalid security principal type!" );
}
principal = (User) authentication.getPrincipal();
}
if ( principal == null ) {
throw new IllegalStateException( "Security principal is not initialized!" );
}
final String loginUrl =
principal.isAdministrator() ? LogoutFilterWrapper.this.logoutSuccessfulUrlAdmin
: LogoutFilterWrapper.this.logoutSuccessfulUrl;
final String timeoutUrl =
LogoutFilterWrapper.this.logoutSuccessfulInactivityUrl
+ "?login="
+ request.getContextPath()
+ loginUrl;
targetUrl = request.getQueryString().contains( "timeout=true" ) ? timeoutUrl : loginUrl;
redirectStrategy.sendRedirect( request, response, targetUrl );
}
}
}
Spring-config
<!-- Register a custom logout filter -->
<beans:bean id="customLogoutFilter" class="com.cramer.srf.security.LogoutFilterWrapper">
<beans:property name="logoutSuccessfulUrl" value="/public/auth/login.htmlx" />
<beans:property name="logoutSuccessfulUrlAdmin" value="/public/auth/admlogin.htmlx" />
<beans:property name="logoutSuccessfulUrlInactivity" value="/public/auth/timedout.htmlx" />
</beans:bean>
5 Comments
Thanks! That worked very well for me!
Thanks for the post. I am new to spring and was looking into you code to put an audit for logout. I implemented this and when the application gets deployed the @PostConstruct method gets called.
But when i logout using /xxxx/xxxx/j_spring_security_logout
The ‘onLogoutSuccess’ method is never called.
My config of this bean is
Am i missing any further configuration (for example in web.xml)
Any help will be appreciated.
Thanks
Jobby
Sorry, the bean configuration did not show up
<bean id=”customLogoutFilter” class=”com.xxxx.web.filter.LogoutFilterWrapper” >
<\bean>
Thanks again
Jobby
hi,
i have a Tag file “head.tag” in that i want to implement the “logout” functionality in spring. . Now i want to call the default “logoutfilter” provided by spring. As i am new to spring i am not able to map that in my “Web.xml” and “spring-security-config.xml” .
So please help me with Filter mapping as i want to redirect to my login page after success. please tell me the process.
please tell me how to call the filter
Post a Comment