Spring Security Custom Login Form Example

In previous posts Spring Security 3 Hello World Example and Spring Security Logout Example, we have used default login form generated by Spring Security framework. Now we'll set up a custom login form for authentication with username and password.

Tools and Technologies used in this article

  1. Spring Framework 3.1.4
  2. Spring Security 3.1.4
  3. JSTL 1.2
  4. Spring Tool Suite 3.2
  5. JDK 1.6
  6. Tomcat 7

1. Overview of this example

This example consists of three pages - custom login page (loginPage.jsp), logout page (logoutPage.jsp) and one page (mypage.jsp) secured by Spring Security framework. User can login using the custom login page and view the secured page for which that particular user is authenticated and authorized. For any failure of authentication, user will be redirected to the custom login page along with a error message describing the reason of failure. On clicking logout link, user will be logged out from the application and redirected to the logout page.

Overall project structure

2. Add and configure

Add and configure in Spring Security configuration xml. If an user tries to access any secured URL, then custom login page will be served based on the configuration of .

File: WEB-INF/spring-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
          http://www.springframework.org/schema/security
          http://www.springframework.org/schema/security/spring-security-3.1.xsd">
           
    <http auto-config="true">
      <intercept-url pattern="/secured/*" access="ROLE_USER" />
        <form-login login-processing-url="/login" login-page="/loginPage"
            username-parameter="username" password-parameter="password"
            default-target-url="/secured/mypage" authentication-failure-url="/loginPage?auth=fail" />
        <logout logout-url="/logout" logout-success-url="/logoutPage" />        
    </http>
     
    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="srccodes" password="password" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
 
</beans:beans>

login-page: Mapping URL of the custom login page. If not defined, then Spring Security will create a default URL at '/spring_security_login' and render a default login form.

login-processing-url: Login form needs to be posted to this URL. If not defined then, it needs to be posted to default URL '/j_spring_security_check'.

username-parameter: Request parameter name which contains the username. Default is 'j_username'.

password-parameter: Request parameter name which contains the password. Default is 'j_password'.

default-target-url: User will be redirected to this URL after successful login.

authentication-failure-url: If authentication failed, then user will be forwarded to this URL. Default is '/spring_security_login?login_error'. In this example we have set it to '/loginPage?auth=fail'. That means user will be redirected to the same login page and there we'll use request parameter 'auth=fail' as indicator to show the authentication failure message.

3. Update Spring MVC Controller

Add handler methods for mapping URLs (/loginPage, /secured/mypage and /logoutPage) in the Spring MVC controller.
File: com/srccodes/spring/controller/SpringSecurityHelloController.java

package com.srccodes.spring.controller;
 
import java.security.Principal;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
/**
 * @author Abhijit Ghosh
 * @version 1.0
 */
 
@Controller
public class SpringSecurityHelloController {
    @RequestMapping("/secured/mypage")
    public String mypage(Model model, Principal principal) {
        String userName = principal.getName();
        model.addAttribute("message", "Hi " + userName + ", Welcome to 'Spring Security Custom Login Form Example'");
 
        return "secured/mypage";
    }
     
    @RequestMapping(value = "/logoutPage", method = RequestMethod.GET)
    public String logoutPage() {
        return "logoutPage";
    }
     
    @RequestMapping(value = "/loginPage", method = RequestMethod.GET)
    public String loginPage() {
        return "loginPage";
    }
}

4. Create Custom Login Form

Create an html form containing two text input fields (username and password) and a Submit button. Set action attribute of the form to login-processing-url ('/login'). Add one block to display authentication failure message. Here we have used 'auth=fail' request parameter (set in authentication-failure-url) to detect whether the user is redirected to this page after a failed attempt or not. ${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message is used to get the error message generated by Spring Security for login failure.

File: WEB-INF/pages/loginPage.jsp

<%@ taglib uri='http://java.sun.com/jsp/jstl/core' prefix='c'%>
<html>
<head>
<title>Login Page</title>
</head>
<body>
    <h2>Custom Form based Login Page</h2>
    <c:if test="${'fail' eq param.auth}">
        <div style="color:red">
                Login Failed!!!<br />
                Reason : ${sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message}
         </div>
    </c:if>
    <form action="${pageContext.request.contextPath}/login" method="post">
        <table>
            <tr>
                <td>Username:</td>
                <td><input type='text' name='username' /></td>
            </tr>
            <tr>
                <td>Password:</td>
                <td><input type='password' name='password'></td>
            </tr>
            <tr>
                <td colspan='2'><input name="submit" type="submit" value="Submit"></td>
            </tr>
        </table>
    </form>
</body>
</html>    

5. Other JSP views

File: WEB-INF/pages/secured/mypage.jsp

<html>
<head>
<title>My Secured Page</title>
</head>
<body>
    <h3>${message}</h3>
    <a href="${pageContext.request.contextPath}/logout">Logout</a>
</body>
</html>   

File: WEB-INF/pages/logoutPage.jsp

<html>
<title>Logout Page</title>
<body>
    <h2>You have been successfully logged out.</h2>
    <a href="${pageContext.request.contextPath}/secured/mypage">Login to My Secured Page</a>
</body>
</html>    

6. Demo

Start the server and deploy the web application. Try to open the URL http://:/spring-security-form-based-login/secured/mypage. You'll be forwarded to custom login page.

Now if you try to login with invalid username and password, you will be redirected to same login page (authentication-failure-url --> '/loginPage?auth=fail') and authentication failure message will also be displayed in the login screen.

Try to authenticate using correct username (srccodes) and password (password). Now you'll be able to view the secured page.

On clicking 'Logout' link, you'll be logged out and forwarded to logout-success-url ('/logoutPage').

Download SrcCodes

All code samples shown in this post are available on GitHub

References