In this tutorial, we will build a complete User Registration and Login System using Spring Boot, Spring Security, Thymeleaf, Bootstrap, HTML 5, and MySQL database.
We are going to use the latest version of Spring boot that is Spring boot 3.
1. Create and Setup Spring Boot Project in IntelliJ
Add below dependencies
- Web
- Spring Data JPA
- MySQL driver
- Thymeleaf
- Lombok
- Validation
Well, we add spring security dependency a bit later.
2. Maven Dependencies
Here is the pom.xml file for your reference:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.0-M4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>registration-login-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>registration-login-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</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-validation</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
Note that we are using the latest version of Spring boot that is Spring boot 3.
3. Configure MySQL Database in Spring Boot App
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=Mysql@123
# Hibernate 6 onwards, you no longer need to use Hibernate dialect
# Hibernate will figure out what Dialect instance to use based on the underlying database server
#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=update
4. Create Thymeleaf Template for Home Page
1. Create Spring MVC Controller - AuthController
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
@Controller
public class AuthController {
@GetMapping("index")
public String home(){
return "index";
}
}
2. Create index.html
- Add bootstrap CDN CSS link
- Add navbar
<!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" href="#">Registration and Login System</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="@{/register}">Register</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<h1> Registration and Login System </h1>
</div>
</div>
</body>
</html>
5. Create User and Role Entities (Many to Many Mapping)
1. User JPA Entity
package com.example.registrationlogindemo.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="users")
public class User
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable=false)
private String name;
@Column(nullable=false, unique=true)
private String email;
@Column(nullable=false)
private String password;
@ManyToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
@JoinTable(
name="users_roles",
joinColumns={@JoinColumn(name="USER_ID", referencedColumnName="ID")},
inverseJoinColumns={@JoinColumn(name="ROLE_ID", referencedColumnName="ID")})
private List<Role> roles = new ArrayList<>();
}
2. Role JPA Entity
package com.example.registrationlogindemo.entity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.List;
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name="roles")
public class Role
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable=false, unique=true)
private String name;
@ManyToMany(mappedBy="roles")
private List<User> users;
}
6. Create UserRepository and RoleRepository
1. UserRepository
package com.example.registrationlogindemo.repository;
import com.example.registrationlogindemo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
User findByEmail(String email);
}
2. RoleRepository
package com.example.registrationlogindemo.repository;
import com.example.registrationlogindemo.entity.Role;
import org.springframework.data.jpa.repository.JpaRepository;
public interface RoleRepository extends JpaRepository<Role, Long> {
Role findByName(String name);
}
7. Create Handler Method to Handle Registration Form Request (add register link in header)
1. Add register link in index.html
<li class="nav-item">
<a class="nav-link active" aria-current="page" th:href="@{/register}">Register</a>
</li>
2. Create UserDto
package com.example.registrationlogindemo.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserDto
{
private Long id;
private String name;
private String email;
private String password;
}
3. Create a handler method to handle user registration request
// handler method to handle user registration request
@GetMapping("register")
public String showRegistrationForm(Model model){
UserDto user = new UserDto();
model.addAttribute("user", user);
return "register";
}
8. User Registration Form Handling
- add header
- add navbar
<!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 fixed-top" th:fragment="header">
<div class="container-fluid">
<a class="navbar-brand" th:href="@{/}">Registration and Login System</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 />
<br />
<div class="container">
<div class="row col-md-8 offset-md-2">
<div class="card">
<div class="card-header">
<h2 class="text-center">Registration</h2>
</div>
<div class="card-body">
<form method="post" role="form" th:action="@{/register/save}" th:object="${user}">
<div class="form-group mb-3">
<label class="form-label">First Name</label>
<input class="form-control"
id="firstName"
name="firstName"
placeholder="Enter first name"
th:field="*{firstName}"
type="text"
/>
<p th:errors="*{firstName}" class="text-danger"
th:if="${#fields.hasErrors('firstName')}">
</p>
</div>
<div class="form-group mb-3">
<label class="form-label">Last Name</label>
<input class="form-control"
id="lastName"
name="lastName"
placeholder="Enter last name"
th:field="*{lastName}"
type="text"
/>
<p th:errors="*{lastName}" class="text-danger"
th:if="${#fields.hasErrors('lastName')}">
</p>
</div>
<div class="form-group mb-3">
<label class="form-label">Email</label>
<input class="form-control"
id="email"
name="email"
placeholder="Enter email address"
th:field="*{email}"
type="email"
/>
<p th:errors="*{email}" class="text-danger"
th:if="${#fields.hasErrors('email')}">
</p>
</div>
<div class="form-group mb-3">
<label class="form-label">Password</label>
<input class="form-control"
id="password"
name="password"
placeholder="Enter password"
th:field="*{password}"
type="password"
/>
<p th:errors="*{password}" class="text-danger"
th:if="${#fields.hasErrors('password')}">
</p>
</div>
<div class="form-group mb-3">
<button class="btn btn-primary" type="submit">Register</button>
<span>Already registered? <a href="/" th:href="@{/login}">Login
here</a></span>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
9. Create Handler Method to Save User Registered Data
1. UserService
package com.example.registrationlogindemo.service;
import com.example.registrationlogindemo.dto.UserDto;
public interface UserService {
void saveUser(UserDto userDto);
}
2. UserServiceImpl
package com.example.registrationlogindemo.service.impl;
import com.example.registrationlogindemo.dto.UserDto;
import com.example.registrationlogindemo.entity.Role;
import com.example.registrationlogindemo.entity.User;
import com.example.registrationlogindemo.repository.RoleRepository;
import com.example.registrationlogindemo.repository.UserRepository;
import com.example.registrationlogindemo.service.UserService;
import org.springframework.stereotype.Service;
import java.util.Arrays;
@Service
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
private RoleRepository roleRepository;
public UserServiceImpl(UserRepository userRepository,
RoleRepository roleRepository) {
this.userRepository = userRepository;
this.roleRepository = roleRepository;
}
@Override
public void saveUser(UserDto userDto) {
User user = new User();
user.setName(userDto.getFirstName() + " " + userDto.getLastName());
user.setEmail(userDto.getEmail());
//encrypt the password once we integrate spring security
user.setPassword(userDto.getPassword());
Role role = roleRepository.findByName("ROLE_ADMIN");
if(role == null){
role = checkRoleExist();
}
user.setRoles(Arrays.asList(role));
userRepository.save(user);
}
private Role checkRoleExist() {
Role role = new Role();
role.setName("ROLE_ADMIN");
return roleRepository.save(role);
}
}
3. Create a handler method to handle registering user form's submit a request
// handler method to handle register user form submit request
@PostMapping("/register/save")
public String registration(@ModelAttribute("user") UserDto user){
userService.saveUser(user);
return "redirect:/register?success";
}
4. Add Registration success message
Just above the card-header, add the below code
<div th:if="${param.success}">
<div class="alert alert-info">You've successfully registered
to our app!</div>
</div>
Here is the complete registration HTML page code:
<!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 fixed-top" th:fragment="header">
<div class="container-fluid">
<a class="navbar-brand" th:href="@{/}">Registration and Login System</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 />
<br />
<div class="container">
<div class="row col-md-8 offset-md-2">
<div class="card">
<div th:if="${param.success}">
<div class="alert alert-info">You've successfully registered
to our app!</div>
</div>
<div class="card-header">
<h2 class="text-center">Registration</h2>
</div>
<div class="card-body">
<form method="post" role="form" th:action="@{/register/save}" th:object="${user}">
<div class="form-group mb-3">
<label class="form-label">First Name</label>
<input class="form-control"
id="firstName"
name="firstName"
placeholder="Enter first name"
th:field="*{firstName}"
type="text"
/>
</div>
<div class="form-group mb-3">
<label class="form-label">Last Name</label>
<input class="form-control"
id="lastName"
name="lastName"
placeholder="Enter last name"
th:field="*{lastName}"
type="text"
/>
</div>
<div class="form-group mb-3">
<label class="form-label">Email</label>
<input class="form-control"
id="email"
name="email"
placeholder="Enter email address"
th:field="*{email}"
type="email"
/>
</div>
<div class="form-group mb-3">
<label class="form-label">Password</label>
<input class="form-control"
id="password"
name="password"
placeholder="Enter password"
th:field="*{password}"
type="password"
/>
</div>
<div class="form-group mb-3">
<button class="btn btn-primary" type="submit">Register</button>
<span>Already registered? <a href="/" th:href="@{/login}">Login
here</a></span>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
10. Adding Validation to User Registration Form
1. Add Validation annotations to UserDto model class
package com.example.registrationlogindemo.dto;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class UserDto
{
private Long id;
@NotEmpty
private String firstName;
@NotEmpty
private String lastName;
@NotEmpty(message = "Email should not be empty")
@Email
private String email;
@NotEmpty(message = "Password should not be empty")
private String password;
}
2. Enable Validation using @Valid annotation at handler method
// handler method to handle register user form submit request
@PostMapping("/register/save")
public String registration(@Valid @ModelAttribute("user") UserDto user){
userService.saveUser(user);
return "redirect:/register?success";
}
3. Use BindingResult to check the errors and return to UI
// handler method to handle register user form submit request
@PostMapping("/register/save")
public String registration(@Valid @ModelAttribute("user") UserDto user,
BindingResult result,
Model model){
userService.saveUser(user);
User existing = userService.findByEmail(user.getEmail());
if (existing != null) {
result.rejectValue("email", null, "There is already an account registered with that email");
}
if (result.hasErrors()) {
model.addAttribute("user", user);
return "register";
}
return "redirect:/register?success";
}
4. Display Errors messages in form input fields
<p th:errors="*{firstName}" class="text-danger"
th:if="${#fields.hasErrors('firstName')}">
</p>
11. Add Spring Security and Use Spring Security’s Default Login and Logout Features
1. Add Spring boot stater security dependency to our app
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. Default user to test Spring Security
The default username is: user and the default password will be printed in the console at the time when your Spring Boot project is starting.
3. Customize the default User with the following properties
spring.security.user.name=ramesh
spring.security.user.password=ramesh
4. Add logout link in index.html
<li class="nav-item">
<a class="nav-link active" aria-current="page" th:href="@{/logout}">Logout</a>
</li>
12. Create Custom Login Form and Configure Spring Security
1. Create a handler method to handle /login request
@GetMapping("/login")
public String loginForm() {
return "login";
}
2. Create Custom Login Form
<!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 fixed-top" th:fragment="header">
<div class="container-fluid">
<a class="navbar-brand" th:href="@{/}">Registration and Login System</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 />
<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 and Password.</div>
</div>
<div class="card">
<div class="card-header">
<h3 class="text-center">Login Form</h3>
</div>
<div class="card-body">
<form
method="post"
th:action="@{/login}"
class="form-horizontal"
role="form"
>
<div class="mb-3">
<label for="username" class="control-label">Email *</label>
<input type="text"
id="username"
name="username"
class="form-control"
placeholder="Email"
/>
</div>
<div class="mb-3">
<label for="password" class="control-label">Password *</label>
<input type="password"
id="password"
name="password"
class="form-control"
placeholder="Password"
/>
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary">Login</button>
<span> Not registered?
<a th:href="@{/register}"> Register/SignUp Here</a>
</span>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
3. Configure Spring Security
package com.example.registrationlogindemo.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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SpringSecurity {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and().
formLogin(
form -> form
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/index")
.permitAll()
);
return http.build();
}
}
13. Logout Feature Implementation
1. Add logout configuration in the SpringSecurity file
.logout(
logout -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.permitAll()
);
Complete code:
package net.javaguides.springboot.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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
public class SpringSecurity {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin(
form -> form
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/admin/posts")
.permitAll()
).logout(
logout -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.permitAll()
);
return http.build();
}
}
2. Add a success logout message on the Login page
<div th:if="${param.error}">
<div class="alert alert-danger">Invalid Email and Password.</div>
</div>
<div th:if="${param.logout}">
<div class="alert alert-success">You have been logged out.</div>
</div>
14. Database Authentication Implementation
1. CustomUserDetailsService Implementation
package com.example.registrationlogindemo.security;
import com.example.registrationlogindemo.entity.Role;
import com.example.registrationlogindemo.entity.User;
import com.example.registrationlogindemo.repository.UserRepository;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Collection;
import java.util.stream.Collectors;
@Service
public class CustomUserDetailsService implements UserDetailsService {
private UserRepository userRepository;
public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email);
if (user != null) {
return new org.springframework.security.core.userdetails.User(user.getEmail(),
user.getPassword(),
mapRolesToAuthorities(user.getRoles()));
}else{
throw new UsernameNotFoundException("Invalid username or password.");
}
}
private Collection < ? extends GrantedAuthority> mapRolesToAuthorities(Collection <Role> roles) {
Collection < ? extends GrantedAuthority> mapRoles = roles.stream()
.map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
return mapRoles;
}
}
2. Database Authentication - Configure Spring Security Configuration
@Autowired
private UserDetailsService userDetailsService;
@Bean
public static PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
Here is the complete Spring Security configuration code:
package com.example.registrationlogindemo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
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.web.SecurityFilterChain;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@Configuration
@EnableWebSecurity
public class SpringSecurity {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public static PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/register/**").permitAll()
.antMatchers("/index").permitAll()
.antMatchers("/users").hasRole("ADMIN")
.and().
formLogin(
form -> form
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/users")
.permitAll()
).logout(
logout -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.permitAll()
);
return http.build();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
}
Demo
Click on the Register link to navigate to the Registration page:
Click on the Login link to navigate to the Login page:
ADMIN user will access this Registered Users Page:
15. Conclusion
Reference
Free Spring Boot Tutorial - 5 Hours Full Course
Watch this course on YouTube at Spring Boot Tutorial | Fee 5 Hours Full Course