In this Spring Security tutorial, we will learn how to create a custom login page to implement Spring Security’s form-based authentication. By default, Spring Security provides a built-in login form to secure the web application. However, most of the time, we need to create a custom login page to meet specific requirements.
Step 1: Create a Spring Boot Project
Using Spring Initializr
- Navigate to Spring Initializr: Open Spring Initializr in your browser.
- Configure the Project:
- Project: Maven Project
- Language: Java
- Spring Boot: 3.2
- Group: com.rameshfadatare
- Artifact: springsecuritycustomlogin
- Name: springsecuritycustomlogin
- Description: Demo project for Spring Boot Security Custom Login Form
- Package name: com.rameshfadatare.springsecuritycustomlogin
- Packaging: Jar
- Java: 17
- Add Dependencies:
- Spring Web
- Spring Security
- Thymeleaf
- Generate the Project: Click on the Generate button to download the project as a zip file.
- Extract the Zip File: Extract the zip file to your preferred location.
Using an IDE
- Open Your IDE: Open your preferred IDE (IntelliJ IDEA, Eclipse, etc.).
- Import the Project: Import the extracted project as a Maven project.
Step 2: Add Maven Dependencies
Ensure your pom.xml
contains the necessary dependencies. It should look something like this:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
Step 3: Create the Spring Security Configuration
Create a SpringSecurityConfig
class under the com.rameshfadatare.springsecuritycustomlogin.config
package and add the following code:
package com.rameshfadatare.springsecuritycustomlogin.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @Configuration public class SpringSecurityConfig { @Bean public static PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeHttpRequests((authorize) -> authorize.anyRequest().authenticated() ).formLogin( form -> form .loginPage("/login") .loginProcessingUrl("/login") .defaultSuccessUrl("/welcome") .permitAll() ).logout( logout -> logout .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .permitAll() ); return http.build(); } @Bean public UserDetailsService userDetailsService() { UserDetails ramesh = User.builder() .username("ramesh") .password(passwordEncoder().encode("password")) .roles("USER") .build(); UserDetails admin = User.builder() .username("admin") .password(passwordEncoder().encode("admin")) .roles("ADMIN") .build(); return new InMemoryUserDetailsManager(ramesh, admin); } }
Explanation
- Password Encoder: The
passwordEncoder()
method creates aBCryptPasswordEncoder
instance for encoding passwords. - Security Filter Chain: The
filterChain()
method configures HTTP security settings, disables CSRF protection, sets up form-based authentication with a custom login page, and configures logout. - In-Memory User Details: The
userDetailsService()
method defines two users,ramesh
andadmin
, and stores them in memory usingInMemoryUserDetailsManager
.
Step 4: Create Thymeleaf Templates
Login Page – login.html
Under the /src/main/resources/templates
folder, create a login.html
file and add the following content:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Login System</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container-fluid"> <a class="navbar-brand" th:href="@{/index}">Spring Security Custom Login Example</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> </div> </nav> <br /><br /> <div class="container"> <div class="row"> <div class="col-md-6 offset-md-3"> <div th:if="${param.error}"> <div class="alert alert-danger">Invalid Email or Password</div> </div> <div th:if="${param.logout}"> <div class="alert alert-success"> You have been logged out.</div> </div> <div class="card"> <div class="card-header"> <h2 class="text-center">Login Form</h2> </div> <div class="card-body"> <form method="post" role="form" th:action="@{/login}" class="form-horizontal"> <div class="form-group mb-3"> <label class="control-label"> Email</label> <input type="text" id="username" name="username" class="form-control" placeholder="Enter email address"/> </div> <div class="form-group mb-3"> <label class="control-label"> Password</label> <input type="password" id="password" name="password" class="form-control" placeholder="Enter password"/> </div> <div class="form-group mb-3"> <button type="submit" class="btn btn-primary">Submit</button> <span> Not registered? <a th:href="@{/register}">Register/Signup here</a> </span> </div> </form> </div> </div> </div> </div> </div> </body> </html>
Welcome Page – welcome.html
Under the /src/main/resources/templates
folder, create a welcome.html
file and add the following content:
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Welcome</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> </head> <body> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <div class="container-fluid"> <a class="navbar-brand" th:href="@{/index}">Spring Security Custom Login Example</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav me-auto mb-2 mb-lg-0"> <li class="nav-item"> <a class="nav-link active" aria-current="page" th:href="@{/logout}">Logout</a> </li> </ul> </div> </div> </nav> <br /><br /> <div class="container"> <div class="row"> <h1> Welcome to Spring Security world!</h1> </div> </div> </body> </html>
Step 5: Create a Spring MVC Controller
Create a WelComeController
class under the com.rameshfadatare.springsecuritycustomlogin.controller
package and add the following code:
package com.rameshfadatare.springsecuritycustomlogin.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class WelComeController { @GetMapping("/welcome") public String greeting() { return "welcome"; } @GetMapping("/login") public String login(){ return "login"; } }
Step 6: Run the Application
- Run the Application: Use your IDE to run the
SpringsecuritycustomloginApplication
class. - Access the Application: Open your browser and go to http://localhost:8080. You should see the custom login page.
Testing the Custom Login Page
- Navigate to the Login Page: Enter http://localhost:8080 in the browser.
- Login: Enter a username as
admin
and password asadmin
, then click the Sign-in button. - After a successful login, you will see the welcome page.
Built-In Logout Feature
Spring Security provides a built-in logout feature. Click on the logout button in the application to log out from the application.
Conclusion
In this Spring Security tutorial, we learned how to create a custom login page to implement Spring Security’s form-based authentication. we also saw that Spring Security provided a built-in logout feature.