Spring Security Custom Login Page with Thymeleaf, HTML 5 and Bootstrap 4
- Details
- Written by Nam Ha Minh
- Last Updated on 31 October 2020   |   Print Email
In this article, I would like to share with you how to code a custom login page in a Spring Boot application with Thymeleaf as the default template engine, HTML 5 for built-in support for field validation, and Bootstrap 4 for responsive user interface.
When Spring Security API is present in the classpath, it will generate the default login page that looks as follows:
This default login is suitable only for quick test, and in practice we almost need to have a custom login page that matches the application’s UI and requires other customizations. The code example below will create a custom login page that looks like the following:
In this custom login page, we have a logo, a headline text, two fields email and password, a checkbox Remember me and a button Login.
1. Configure Custom Login Page in Spring Security Configuration Class
First, you need to specify URL of the custom login page in the Spring Security configuration class as follows:
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() ... .formLogin() .loginPage("/login") .usernameParameter("email") .permitAll() .and() .logout().permitAll() .and().rememberMe() .tokenRepository(persistentTokenRepository()) ... } }
As you can see, the login page URL is /login, so you need to have a handler method for this URL in a Spring MVC controller. For example:
@Controller public class CommonController { ... @GetMapping("/login") public String viewLoginPage() { // custom logic before showing login page... return "login"; } }
As you can see, the handler method returns the logical view name login which will be resolved to the login.html file by Thymeleaf template engine.
If you don’t have any custom logic that needs to be performed before showing the login page, you can simply specify the view name resolution in a Spring MVC configuration class as shown in the code snippet below:
@Configuration public class MvcConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("login"); } }
You can also note that we use different name for the username field in the custom login form, e.g. email:
.formLogin() .loginPage("/login") .usernameParameter("email")
Check this article for more customizations of the form login. This article focuses on the code of the custom login page only.
2. Code Custom Login Page with Thymeleaf, HTML and Bootstrap
For your reference, below is the full code of the custom login page – login.html under src/main/resources/templates directory (all the CSS classes are from Bootstrap):
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"> <title>Login - Shopme Admin</title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" /> </head> <body> <div class="container-fluid text-center"> <div> <img class="img-fluid" th:src="/@{/images/ShopmeAdminBig.png}" /> </div> <form th:action="@{/login}" method="post" style="max-width: 350px; margin: 0 auto;"> <div th:if="${param.error}"> <p class="text-danger">[[${session.SPRING_SECURITY_LAST_EXCEPTION.message}]]</p> </div> <div th:if="${param.logout}"> <p class="text-warning">You have been logged out.</p> </div> <div class="border border-secondary p-3 rounded"> <p>Access to Shopme Control Panel</p> <p> <input type="email" name="email" class="form-control" placeholder="E-mail" required autofocus/> </p> <p> <input type="password" name="password" class="form-control" placeholder="Password" required /> </p> <p> <input type="checkbox" name="remember-me" /> Remember Me </p> <p> <input type="submit" value="Login" class="btn btn-primary" /> </p> </div> </form> </div> </body> </html>
You should declare a XML namespace so you can use Thymeleaf tags and attributes with the prefix th in the HTML document:
<html xmlns:th="http://www.thymeleaf.org">
The following meta tag will make the page responsive on different devices:
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
The following link for using Bootstrap version 4.4.1 from a CDN website:
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous" />
To display the logo image, you should put an image file under the src/main/resources/static/images directory:
<img class="img-fluid" th:src="/@{/images/ShopmeAdminBig.png}" />
For the input fields, we use field type email and password so the browser will validate the email automatically. And use the attribute required for both email and password so the browser will check fields not empty:
<input type="email" name="email" class="form-control" placeholder="E-mail" required autofocus/> <input type="password" name="password" class="form-control" placeholder="Password" required />
So with HTML 5, you don’t have to write a single line of Javascript code to validate the form. Very convenient!
And note that, to display the original error message in case failed login, you should print message of the SPRING_SECURITY_LAST_EXCEPTION object from the session like this:
<div th:if="${param.error}"> <p class="text-danger">[[${session.SPRING_SECURITY_LAST_EXCEPTION.message}]]</p> </div>
That’s code example of a Spring Security custom login page with Thymeleaf, HTML 5 and Bootstrap. To see the coding in action, you can watch the following video:
Related Spring Security Tutorials:
- Spring Security Authentication with JPA, Hibernate and MySQL
- Spring Security Role-based Authorization Tutorial
- Spring Security Customize Login and Logout
- How to Get Logged-in User's Details with Spring Security
- Spring Security: Prevent User from Going Back to Login Page if Already logged in
- Spring Security Authentication Success Handler Examples
- Spring Security Authentication Failure Handler Examples
- Spring Security Logout Success Handler Example
- Spring Security Before Authentication Filter Examples
Other Spring Boot Tutorials:
- How to create a Spring Boot Web Application (Spring MVC with JSP/ThymeLeaf)
- Spring Boot CRUD Example with Spring MVC – Spring Data JPA – ThymeLeaf - Hibernate - MySQL
- Spring Boot Hello World RESTful Web Services Tutorial
- Spring Boot Thymeleaf Form Handling Tutorial
- Spring Data JPA Paging and Sorting Examples
- Spring Boot Error Handling Guide
- Spring Boot Logging Basics
Comments
You need to have the Spring boot starter security dependency present in the project's classpath.