Fork me on GitHub

Programming, Internet & more

Custom login page with JSF and Spring-Security 3

Spring-Security is great, but it is mostly used together with spring-mvc. It works well with JSF also but there are a few pitfalls, you can come across if you haven’t used spring-security with JSF before. In this tutorial I will explain how to provide a custom login page implemented in JSF for spring-security.


  • You should have spring-security together with jsf up and running.

JSF login page

First of all, a custom login page must be created. It can be a simple JSF-page but there must some fields with their appropriate id’s. Please make sure the id’s are exactly the same as shown below. Here is my login.jsf:

  <h:form id="loginForm" prependId="false">
    <!-- Messages must be global here, to show bad credentials -->
    <h:messages globalOnly="true"/>
    <!-- Id's must not be changed to support spring security check -->
    <h:panelGrid columns="3">
    <h:outputLabel for="j_username" value="User: * " />  
    <h:inputText id="j_username" required="true" label="username" />  
    <h:message for="j_username" display="text" style="color:red"/>
    <h:outputLabel for="j_password" value="Password: * " />  
    <h:inputSecret id="j_password" label="password" required="true" />  
    <h:message for="j_password" display="text" style="color:red"/>
    <h:outputLabel for="_spring_security_remember_me" value="Remember me: " />
    <h:selectBooleanCheckbox    id="_spring_security_remember_me" />        
    <h:commandButton type="submit" id="login" value="Login"
        action="#{loginController.doLogin}" />

Login controller

To get the login page working, a controller must be provided. Therefore you’ve to create a managedBean with the name loginController. The controller will do a redirect to the standard spring-security check page, which would also be used by the standard spring login page.

Please note that the controller must implement the PhaseListener interface. This is needed to provide feedback to the user if the login was unsuccessful or some required fields are missing. Here is the LoginController:

package de.slackspace.tutorials.customloginpage;


import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LoginController implements PhaseListener {

     protected final Log logger = LogFactory.getLog(getClass());
     * Redirects the login request directly to spring security check.
     * Leave this method as it is to properly support spring security.
     * @return
     * @throws ServletException
     * @throws IOException
    public String doLogin() throws ServletException, IOException {
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();

        RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())

        dispatcher.forward((ServletRequest) context.getRequest(),
                (ServletResponse) context.getResponse());


        return null;

    public void afterPhase(PhaseEvent event) {

    /* (non-Javadoc)
     * @see javax.faces.event.PhaseListener#beforePhase(javax.faces.event.PhaseEvent)
     * Do something before rendering phase.
    public void beforePhase(PhaseEvent event) {
        Exception e = (Exception) FacesContext.getCurrentInstance().
        if (e instanceof BadCredentialsException) {
            logger.debug("Found exception in session map: "+e);
                    WebAttributes.AUTHENTICATION_EXCEPTION, null);
              new FacesMessage(FacesMessage.SEVERITY_ERROR,
                "Username or password not valid.", "Username or password not valid"));

    /* (non-Javadoc)
     * @see javax.faces.event.PhaseListener#getPhaseId()
     * In which phase you want to interfere?
    public PhaseId getPhaseId() {
        return PhaseId.RENDER_RESPONSE;


To keep the project structure neat and clean, I have a separate spring config for spring-security. To use it, you have to define a context-param in the web.xml.


To enable the login page to redirect to the standard spring security check page, we have to enable that also in web.xml.

<!-- Enable Spring Security -->
<!-- Allow login pages with JSF which redirects to security check,
 therefore we have to add the forward entry here -->


The last step is to define the new custom login page in security.xml. We can use the spring login-page property for this.

<http use-expressions="true">
        <!-- Custom login page -->
        <form-login login-page="/login.jsf" />        


Now you can use the JSF login page. If you try to access a protected page, you should get your JSF login page instead of the default one.


You can find a full working example at GitHub.

Category: spring


Leave a Reply

Your email address will not be published. Required fields are marked *