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. But, most of the time we need create custom Login page as per our requirement.
Maven 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>
Spring Security Configuration
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);
}
}
When the login page is specified in the Spring Security configuration, you are responsible for rendering the page.
Thymeleaf Template - Custom Login Page
The following Thymeleaf template produces an HTML login form that complies with a login page of /login.
Login Form - src/main/resources/templates/login.html
<!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>
There are a few key points about the custom Login HTML form:
- The form should perform a post to /login.
- The form should specify the username in a parameter named username.
- The form should specify the password in a parameter named password.
- If the HTTP parameter named error is found, it indicates the user failed to provide a valid username or password.
- If the HTTP parameter named logout is found, it indicates the user has logged out successfully.
- Many users do not need much more than to customize the login page. However, if needed, you can customize everything shown earlier with additional configuration.
Spring MVC Controller
Let's create a handler method in the Spring MVC controller that maps GET /login to the login template we created:
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";
}
}
Note that we have also created a welcome handler method to return the welcome Thymeleaf template page.
Thymeleaf Template - welcome.html
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org"
>
<head>
<meta charset="UTF-8">
<title>Registration and 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 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 />
<body>
<div class="container">
<div class="row">
<h1> Welcome to Spring Security world!</h1>
</div>
</div>
</body>
</html>
Test Custom Login Page using Browser
Enter the URL http://localhost:8080 in the browser, and it will navigate to the login page. Next, enter a username as admin, password as admin, and click on the Sign-in button:
After successful login, you will see the below web page:
Built-In Logout Feature
Conclusion
In this Spring Security tutorial, we learned how to create a custom login page to implement Spring Security's form-based authentication.
Comments
Post a Comment
Leave Comment