I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE COURSE

1. Overview

In this article we’re going to illustrate how to implement a simple Login Page with Spring MVC for an application that’s handling the authentication with Spring Security in the backend.

For the full details on how to handle login with Spring Security, here’s the article going in depth into the configuration and implementation of that.

2. The Login Page

Let’s start by defining a very simple login page:

<html>
<head></head>
<body>
   <h1>Login</h1>
   <form name='f' action="login" method='POST'>
      <table>
         <tr>
            <td>User:</td>
            <td><input type='text' name='username' value=''></td>
         </tr>
         <tr>
            <td>Password:</td>
            <td><input type='password' name='password' /></td>
         </tr>
         <tr>
            <td><input name="submit" type="submit" value="submit" /></td>
         </tr>
      </table>
  </form>
</body>
</html>

Now, let’s include a client side check to make sure the username and password have been entered before we even submit the form. For this example we’ll use plain Javascript, but JQuery is an excellent option as well:

<script type="text/javascript">
function validate() {
    if (document.f.username.value == "" && document.f.password.value == "") {
        alert("Username and password are required");
        document.f.username.focus();
        return false;
    }
    if (document.f.username.value == "") {
        alert("Username is required");
        document.f.username.focus();
        return false;
    }
    if (document.f.password.value == "") {
	alert("Password is required");
	document.f.password.focus();
        return false;
    }
}
</script>

As you can see, we simply check if the username or password fields are empty; if they are – a javascript message box will pop up with the corresponding message.

3. Message Localization

Next – let’s localize the messages we’re using on the front end. There are types of such messages, and each is localized in a different manner:

  1. Messages generated before the form is processed by Spring’s controllers or handlers. These messages ca be referenced in the JSP pages and are localized with Jsp/Jslt localization (see Section 4.3.)
  2. Messages that are localized once a page has been submitted for processing by Spring (after submitting the login form); these messages are localized using Spring MVC localization (See Section 4.2.)

3.1. The message.properties files

In either case, we need to create a message.properties file for each language we want to support; the names of the files should follow this convention: messages_[localeCode].properties.

For example, if we want to support English and Spanish error messages we would have the file: messages_en.properties and messages_es_ES.properties. Note that, for English – messages.properties is also valid.

We’re going to place these two files in the project’s classpath (src/main/resources). The files simply contain the error codes and messages we need to display in different languages – for example:

message.username=Username required
message.password=Password required
message.unauth=Unauthorized access!!
message.badCredentials=Invalid username or password
message.sessionExpired=Session timed out
message.logoutError=Sorry, error login out
message.logoutSucc=You logged out successfully

3.2. Configuring Spring MVC Localization

Spring MVC provides a LocaleResolver that works in conjunction with its LocaleChangeInterceptor API to make possible the display of messages in different languages, depending on the locale setting. To configure localization – we need to define the following beans in our MVC configuration:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
    localeChangeInterceptor.setParamName("lang");
    registry.addInterceptor(localeChangeInterceptor);
}
@Bean
public LocaleResolver localeResolver() {
    CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
    return cookieLocaleResolver;
}
@Bean
public MessageSource messageSource() {
    ReloadableResourceBundleMessageSource messageSource = 
      new ReloadableResourceBundleMessageSource();
    messageSource.setBasename("classpath:messages");
    messageSource.setUseCodeAsDefaultMessage(true);
    messageSource.setDefaultEncoding("UTF-8");
    messageSource.setCacheSeconds(0);
    return messageSource;
}

One important and more advanced note here is that we need to make sure that the messageSource bean is defined in the right Spring context – the context that it’s going to be used in. Keep in mind that the web app has the root context and then it has one (or more) servlet contexts.

By default, the locale resolver will obtain the locale code from the HTTP header. To force a default locale, we need to set it on the localeResolver():

@Bean
public LocaleResolver localeResolver() {
    CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
    cookieLocaleResolver.setDefaultLocale(Locale.ENGLISH);
    return cookieLocaleResolver;
}

This locale resolver is a CookieLocaleResolver which means that it stores the locale information in a client side cookie; as such – it will remember the user’s locale every time they log in, and during the entire visit.

Alternatively there is a SessionLocaleResolver, which remembers the locale throughout the session. To use this LocaleResolver instead, we need to replace the above method with the following:

@Bean
public LocaleResolver localeResolver() {
    SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
    return sessionLocaleResolver;
}

Lastly, note that the LocaleChangeInterceptor will change the locale based on the value of a lang parameter sent with the login page by simple links:

<a href="?lang=en">English</a> |
<a href="?lang=es_ES">Spanish</a>

3.3. JSP/JSLT Localization

JSP/JSLT API will be used to display localized messages that are caught in the jsp page itself. To use the jsp localization libraries we should add the following dependencies to the pom.xml:

<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.2-b01</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

4. Displaying Error Messages

4.1. Login Validation Errors

In order to use the JSP/JSTL support and display localized messages in the login.jsp lets implement the following changes in the page:

1. Add the following tag lib element to the login.jsp:

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>

2. Add the jsp/jslt element that will point to the messages.properties files:

<fmt:setBundle basename="messages" />

3. Add the following <fmt:…> elements to store the messages on jsp variables:

<fmt:message key="message.password" var="noPass" />
<fmt:message key="message.username" var="noUser" />

4. Modify the login validation script we saw in Section 3 so as to localize the error messages:

<script type="text/javascript">
function validate() {
    if (document.f.username.value == "" && document.f.password.value == "") {
        alert("${noUser} and ${noPass}");
	document.f.username.focus();
	return false;
    }
    if (document.f.username.value == "") {
	alert("${noUser}");
	document.f.username.focus();
	return false;
     }
     if (document.f.password.value == "") {
	alert("${noPass}");
	document.f.password.focus();
	return false;
     }
}
</script>

4.2. Pre Login Errors

Sometimes the login page will be passed an error parameter if the previous operation failed. For example, a registration form submit button will load the login page. If the registration was successful, then it would be a good idea to show a success message in the login form, and an error message if the opposite was true.

In the sample login form below, we are implementing this by intercepting and regSucc and regError parameters, and displaying a localized message based on their values.

<c:if test="${param.regSucc == true}">
    <div id="status">
	<spring:message code="message.regSucc">    
        </spring:message>
    </div>
</c:if>
<c:if test="${param.regError == true}">
    <div id="error">
        <spring:message code="message.regError">   
        </spring:message>
    </div>
</c:if>

4.3. Login Security Errors

In case the login process fails for some reason, Spring Security will do a redirect to a login error URL, which we have defined to be /login.html?error=true.

So – similarly to how we have shown the status of the registration in the page, we need to do the same in case of a login problem:

<c:if test="${param.error != null}">
    <div id="error">
        <spring:message code="message.badCredentials">   
        </spring:message>
    </div>
</c:if>

Notice that we are using a <spring:message …> element. This means that the error messages are generated during the Spring MVC processing.

The full login page – including the js validation and these additional status messages can be found in the github project.

4.4. Logout Errors

In the example that follows, the jsp code <c:if test=”${not empty SPRING_SECURITY_LAST_EXCEPTION}”> in the logout.html page will check if there was an error in the logout process.

For example – if there is a persistence exception when a custom logout handler tries to store user data before redirecting to the logout page. While these errors are rare, we should handle them as neatly as possible as well.

Lets take a look at the complete logout.jsp:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec"
    uri="http://www.springframework.org/security/tags"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<c:if test="${not empty SPRING_SECURITY_LAST_EXCEPTION}">
    <div id="error">
        <spring:message code="message.logoutError">    
        </spring:message>
    </div>
</c:if>
<c:if test="${param.logSucc == true}">
    <div id="success">
	<spring:message code="message.logoutSucc">    
        </spring:message>
    </div>
</c:if>
<html>
<head>
<title>Logged Out</title>
</head>
<body>	
    <a href="login.html">Login</a>
</body>
</html>

Notice that the logout page also reads the query string param logSucc, and if its value equal to true, a localized success message will be displayed.

5. The Spring Security Configuration

The focus of this article is the frontend of the login process, not the backend – so we’ll look only briefly at the main points of the security configuration; for the full config, you should read the previous article.

5.1. Redirecting to the Login Error URL

The following directive in the <form-login…/> element directs the flow of the application to the url where the login error will be handled:

authentication-failure-url="/login.html?error=true"

5.2. The Logout Success Redirect

<logout 
  invalidate-session="false" 
  logout-success-url="/logout.html?logSucc=true" 
  delete-cookies="JSESSIONID" />

The logout-success-url attribute simply redirects to the logout page with a parameter that confirms that the logout was successful.

6. Conclusion

In this article we have illustrated how to implement a Login page for a Spring Security backed application – handling login validation, displaying authentication errors and message localization.

We’re going to be looking at a full registration implementation in the next article – with the goal of having a full implementation of the login and registration process ready for production.

I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE LESSONS

Sort by:   newest | oldest | most voted
Saúl de León Guerrero
Guest
Saúl de León Guerrero
Hi Eugen, and thank you for this post. im trying to create my own custom validation handling class, but im getting completely stuck at this point. The thing is that im trying to generate al the Exceptions on the server side, and then return a list of errors p.e *Username is empty *Password is empty or *Username doesn’t exist But all of this errors are generated on the server side, not in the front side. Is this possible to ahieve? I have tryed lot of solutions and no one works properly for me. What do you suggest? There is some… Read more »
Eugen Paraschiv
Guest

Hey Saúl,
So – let me first see if I properly understand your question. You’re saying that all of these validation errors are generated on the server side. This is normal one you sent out the POST request. Now – you can also do a lot of validation on the client side as well – and simply not send the request before everything is valid. But – once you do sent the request – the server side does the validation.
Is that what you were asking or did I miss the point? Cheers,
Eugen.

Saúl de León Guerrero
Guest
Saúl de León Guerrero
thanks for your reply! Yeah, im just learning the error handling of authentication of Spring and would like to generate al this errors(which i know can be generated on the front side as seen in this example with JS) in the server side only, not in the front side I have been searching and searching and i think that first i have to create a “ExceptionMappingAuthenticationFailureHandler” and add it to the .failureHandler() option in SpringSecurityConfig.java. After that, im able to catch all those exceptions and map it to a controller of my decision, p.e if a BadCredentialsException is launched, i… Read more »
Eugen Paraschiv
Guest

The best way to go about that is to use the technique I described here. Now – the localization part – you have to do by hand. Basically – you just inject the message resolver and do localization normally – when you form your response. Hope that helps. Cheers,
Eugen.

wpDiscuz