April 27th, 2009 by
Lincoln Baxter III
Revisited – Acegi/Spring Security & JSF Login Page
A correction has been made to the post:
http://ocpsoft.com/java/acegi-spring-security-jsf-login-page/, fixing an issue where FacesMessages were not being displayed on failed authentications.
Because the example had initially used the @PostConstruct annotation to trigger a method to handle the error message, the handleError() method was being called before the actual authentication event had taken place, thus, the handleError() method was triggering before any BadCredentialsExceptions were stored in the Session.
Instead of creating an error handling method in the LoginBean itself, instead attach a PhaseListener which will intercept failed logins, and add the new FacesMessage before the RENDER_RESPONSE phase.
LoginErrorPhaseListener
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.ui.AbstractProcessingFilter;
impot util.FacesUtils;
public class LoginErrorPhaseListener implements PhaseListener
{
private static final long serialVersionUID = -1216620620302322995L;
@Override
public void beforePhase(final PhaseEvent arg0)
{
Exception e = (Exception) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(
AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY);
if (e instanceof BadCredentialsException)
{
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(
AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY, null);
FacesUtils.addErrorMessage("Username or password not valid.");
}
}
@Override
public void afterPhase(final PhaseEvent arg0)
{}
@Override
public PhaseId getPhaseId()
{
return PhaseId.RENDER_RESPONSE;
}
} |
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.ui.AbstractProcessingFilter;
impot util.FacesUtils;
public class LoginErrorPhaseListener implements PhaseListener
{
private static final long serialVersionUID = -1216620620302322995L;
@Override
public void beforePhase(final PhaseEvent arg0)
{
Exception e = (Exception) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(
AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY);
if (e instanceof BadCredentialsException)
{
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(
AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY, null);
FacesUtils.addErrorMessage("Username or password not valid.");
}
}
@Override
public void afterPhase(final PhaseEvent arg0)
{}
@Override
public PhaseId getPhaseId()
{
return PhaseId.RENDER_RESPONSE;
}
}
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<lifecycle>
<phase-listener>login.LoginErrorPhaseListener</phase-listener>
</lifecycle>
</faces-config> |
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<lifecycle>
<phase-listener>login.LoginErrorPhaseListener</phase-listener>
</lifecycle>
</faces-config>
Happy developing!
Posted in
JSF, Spring