How to implement Spring Boot Thymeleaf Security Login Example? Spring Boot java Spring by shwetas8536 - March 17, 2024October 20, 202428 Last Updated on October 20th, 2024In continuation to previous article on two different ways of implementing Spring Security, here in this article we will learn the third way ‘How to implement Spring Boot Thymeleaf Security Login Example using UserDetailsService?’. After going through the previous article, I hope we all are very familiar with basics of Security and even the basics of Security in a Spring Boot application. This time we will create a user registration form and save users with their roles into database. Then, based on the user role, we will check the authentication and authorization functionalities with the help of predefined UserDetailsService. If you are looking for ‘How to implement Security in Spring Boot using UserDetailsService with Spring Boot 3 onward?, kindly visit a separate article on Spring Security UserDetailsService Using Spring Boot 3. To illustrate, we will take some roles into effect and play around them in the whole process to make it crystal clear. Additionally, we will have some pages and restrict them to be accessible by some specific roles only. Equally important, we will have to create a small MVC web application to make registration process open for users. Users will enter their roles while doing registration. Then we can implement security features on top of it. Let’s start working on our topic ‘How to implement Spring Boot Thymeleaf Security Login Example using UserDetailsService?’ accordingly. Table of Contents Toggle What can you expect from this article on the whole?What is UserDetailsService all about ? What is the benefit of using it?How to implement UserDetailsService Security in our application ?How does UserDetailsService internally work in Spring Security application ?Example: How to implement Spring Boot Thymeleaf Security Login Example using UserDetailsService?What Software/Technologies would you need?Step#1: Create a Spring Boot Starter Project in STS(Spring Tool Suite)Step#2: Update database properties in application.properties fileStep#3: Create User Entity & Repository classesStep#4: Create AppConfig class to instantiate BCryptPasswordEncoderStep#5: Create Service Interface & Service Implementation classStep#6: Create a UserController classStep#7: Write a Controller class to navigate through pagesStep#8: Write UI pages(Thymeleaf) Step#9: Write SecurityConfig classStep#9A: Write SecurityConfig class Without Using WebSecurityConfigurerAdapterHow to test the security enabled Application ?Summary What can you expect from this article on the whole? 1) What is an UserDetailsService concept in the context of Spring Security? 2) What is the benefits of implementing UserDetailsService? 3) How to implement Spring Boot Thymeleaf Security Login Example using UserDetailsService? 4) How does UserDetailsService internally work in Spring Security application with flow diagram? 5) Moreover, how to use annotations :@EnableWebSecurity, @Configuration, @Bean, @GetMapping, @Autowired, @Data, @Entity, @Table, @Id, @GeneratedValue, @Column, @ElementCollection, @CollectionTable, @JoinColumn, @Service 6) How to develop a user registration app using Spring MVC with Thymeleaf? 7) How to test the Security enabled application? 8) How to implement Security in Spring Boot using UserDetailsService Without WebSecurityConfigurerAdapter? What is UserDetailsService all about ? What is the benefit of using it? UserDetailsService is a predefined interface exists under package org.springframework.security.core.userdetails in Spring. Our implementation class implements this interface and overrides it’s loadUserByUsername(String username) method. This method returns UserDetails which is again an interface. Predefined User class (org.springframework.security.core.userdetails.User) is an implementation of UserDetails interface. In summary, in loadUserByUsername(String username) method we pass our username and it returns us predefined User object(org.springframework.security.core.userdetails.User). In fact, we provide only username to UserDetailsService and some small configurations and we get all role based security functionality implemented as part of the framework. Accordingly, we save a lot of effort in implementing security. How to implement UserDetailsService Security in our application ? First of all, you must have a Spring Boot web application where in you will have a form i.e. a kind of User registration form. As part of the Spring MVC structure you will have a UserService implementation class. Let’s say it UserServiceImpl.java. The second thing to remember is that you have to convert your User object into predefined Spring’s User object. Further, please follow below steps to get UserDetailsService implemented in your application. 1) Your user service class ‘UserServiceImpl.java’ should implement interface UserDetailsService.java(Provided by Spring) 2) Equally important, Override loadUserByUsername(String username) method of interface UserDetailsService in your UserServiceImpl class. 3) As part of implementation, (A) Get your User Object with the help of username/email from UserRepository. (B) Convert your User Object into Spring’s predefined User object(org.springframework.security.core.userdetails.User) accordingly. (C) Return Spring defined User object which is an implementation of UserDetails(method’s return type). Below code represents the implementation of UserDetailsService. However, you will see the complete code in below sections consequently. UserServiceImpl.java @Servicepublic class UserServiceImpl implements IUserService, UserDetailsService{ @Autowired private UserRepository userRepo; @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { Optional<User> opt = userRepo.findUserByEmail(email); org.springframework.security.core.userdetails.User springUser=null; if(opt.isEmpty()) { throw new UsernameNotFoundException("User with email: " +email +" not found"); }else { User user =opt.get(); List<String> roles = user.getRoles(); Set<GrantedAuthority> ga = new HashSet<>(); for(String role:roles) { ga.add(new SimpleGrantedAuthority(role)); } springUser = new org.springframework.security.core.userdetails.User( email, user.getPassword(), ga ); } return springUser; } //Other Approach: Using Lambda & Stream API of Java 8 /*@Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { Optional<User> opt = userRepo.findUserByEmail(email); if(opt.isEmpty()) throw new UsernameNotFoundException("User with email: " +email +" not found !"); else { User user = opt.get(); return new org.springframework.security.core.userdetails.User( user.getEmail(), user.getPassword(), user.getRoles() .stream() .map(role-> new SimpleGrantedAuthority(role)) .collect(Collectors.toSet()) ); }*/} How does UserDetailsService internally work in Spring Security application ? As soon as the user enters username & password and click on the Login button, WebSecurityConfigurerAdapter is called which internally calls UserServiceImpl.java (Implementation class, provided by the programmer). Furthermore, loadUserByUserName( ) method implemented in UserServiceImpl.java converts our User Object into Spring provided User object. Also, our SecurityConfig.java extends WebSecurityConfigurerAdapter and provides an implementation of authentication & authorization logics in two methods; configure(AuthenticationManagerBuilder) & configure(HttpSecurity) respectively as shown in below code. SecurityConfig.java @EnableWebSecurity@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService uds; @Autowired private BCryptPasswordEncoder encoder; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(uds).passwordEncoder(encoder); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/home","/register","/saveUser").permitAll() .antMatchers("/welcome").authenticated() .antMatchers("/admin").hasAuthority("Admin") .antMatchers("/mgr").hasAuthority("Manager") .antMatchers("/emp").hasAuthority("Employee") .antMatchers("/hr").hasAuthority("HR") .antMatchers("/common").hasAnyAuthority("Employeee,Manager,Admin") .anyRequest().authenticated() .and() .formLogin() .defaultSuccessUrl("/welcome",true) .and() .logout() .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .and() .exceptionHandling() .accessDeniedPage("/accessDenied"); }} Note: Spring Security 5.7.0-M2 onward, WebSecurityConfigurerAdapter has been deprecated. Hence, If you are using Spring Security 5.7.0-M2 or later versions, please update your implementation as shown in below code snippet. Moreover, in order to learn the new way of implementing custom configuration class, visit a separate article on Spring Security without WebSecurityConfigurerAdapter. SecurityConfig.java package com.dev.springboot.security.UserDetailsService.config;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.AuthenticationProvider;import org.springframework.security.authentication.dao.DaoAuthenticationProvider;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.web.SecurityFilterChain;import org.springframework.security.web.util.matcher.AntPathRequestMatcher;@EnableWebSecurity@Configurationpublic class SecurityConfig { @Autowired private UserDetailsService uds; @Autowired private BCryptPasswordEncoder encoder; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/home","/register","/saveUser").permitAll() .antMatchers("/welcome").authenticated() .antMatchers("/admin").hasAuthority("Admin") .antMatchers("/mgr").hasAuthority("Manager") .antMatchers("/emp").hasAuthority("Employee") .antMatchers("/hr").hasAuthority("HR") .antMatchers("/common").hasAnyAuthority("Employeee,Manager,Admin") .anyRequest().authenticated() .and() .formLogin() .defaultSuccessUrl("/welcome",true) .and() .logout() .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .and() .exceptionHandling() .accessDeniedPage("/accessDenied") .and() .authenticationProvider(authenticationProvider()); return http.build(); } @Bean public AuthenticationProvider authenticationProvider() { DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); authenticationProvider.setUserDetailsService(uds); authenticationProvider.setPasswordEncoder(encoder); return authenticationProvider; }} Example: How to implement Spring Boot Thymeleaf Security Login Example using UserDetailsService? To illustrate the implementation of UserDetailsService, let’s assume an internal portal of a small company. In company we have various roles within employees such as Admin, HR, Manager and of course Employee as well. Additionally, the Portal has role based access to pages. Even Some pages are accessible to all roles while others are restricted to some particular roles. Equally important, the company will have a user registration page which must be accessible to all users, even without login. Now let’s create a standard user registration flow as given below. What Software/Technologies would you need? ♦STS (Spring Tool Suite) : Version-> 4.7.1.RELEASE ⇒Dependent Starters : Spring Security, Thymeleaf, Spring Web, Lombok, Spring Data JPA, MySQL Driver, Spring Boot DevTools ♦MySQL Database : Version ->8.0.19 MySQL Community Server ♦JDK8 or later versions (Extremely tested on JDK8, JDK11 and JDK14) Let’s follow below steps to develop a small web application and then apply UserDetailsService security into it. Step#1: Create a Spring Boot Starter Project in STS(Spring Tool Suite) While creating Starter Project select ‘Spring Security’, ‘Thymeleaf’, ‘Spring Web’, ‘Spring Data JPA’, ‘MySQL Driver’, ‘Lombok’ and ‘Spring Boot DevTools’ as starter project dependencies. Even If you don’t know how to create a Spring Boot Starter Project, Kindly visit Internal Link. Also, if you want to know more about Lombok, then visit Internal Link on Lombok. Step#2: Update database properties in application.properties file Update application.properties to connect to MySQL DB accordingly. Please note that we can omit driver-class-name as Spring Boot will automatically find it from the database URL as shown below. #application.properties --------------------------------------------------------------------- #-------------------- server properties --------------- server.port=8080 #--------------------- DB Connection ------------------ #AutoLoading of driver class since JDBC 4 #spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/testBootSecurity spring.datasource.username=root spring.datasource.password=devs #--------------------JPA-ORM Properties----------------- spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=update #spring.jpa.database-platform=org.hibernet.dialect.MySQL8Dialect Step#3: Create User Entity & Repository classes Now create User.java & UserRepositoty.java as below. Equally important, User.java has a variable ‘roles’ of type List<String>. It will create a separate table in the database with two columns user_id and user_role accordingly. Further, @ElementCollection(fetch= FetchType.EAGER) indicates that while fetching User object, also fetch roles simultaneously. On the other hand, UserRepository extends ‘JpaRepository’ to taking advantage of inbuilt database operations. User.java package com.dev.springboot.security.UserDetailsService.model;import java.util.List;import javax.persistence.CollectionTable;import javax.persistence.Column;import javax.persistence.ElementCollection;import javax.persistence.Entity;import javax.persistence.FetchType;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.Table;import lombok.Data;@Data@Entity@Table(name="users")public class User { @Id @GeneratedValue @Column(name="user_id") private Integer id; @Column(name="user_name") private String name; @Column(name="user_passwd") private String password; @Column(name="user_email") private String email; @ElementCollection(fetch= FetchType.EAGER) @CollectionTable( name="roles", joinColumns = @JoinColumn(name="user_id") ) @Column(name="user_role") private List<String> roles; } UserRepository.java package com.dev.springboot.security.UserDetailsService.repo;import java.util.Optional;import org.springframework.data.jpa.repository.JpaRepository;import com.dev.springboot.security.UserDetailsService.model.User;public interface UserRepository extends JpaRepository<User, Integer> { Optional<User> findUserByEmail(String email);} Step#4: Create AppConfig class to instantiate BCryptPasswordEncoder As BCryptPasswordEncoder is a predefined class, hence we need to provide it’s instantiation code in AppConfig.java as a configuration class. Further, BCryptPasswordEncoder will be required to encode our password values in other classes. AppConfig.java package com.dev.springboot.security.UserDetailsService.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;@Configurationpublic class AppConfig { @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }} Step#5: Create Service Interface & Service Implementation class Create Service Interface and Service Impl class as IUserService.java and UserServiceImpl.java accordingly as shown below. In fact, implementation of loadUserByUsername(String email) method in UserServiceImpl.java is the most important part of your UserDetailsService on the whole. IUserService.java package com.dev.springboot.security.UserDetailsService.service;import com.dev.springboot.security.UserDetailsService.model.User;public interface IUserService { public Integer saveUser(User user);} UserServiceImpl.java package com.dev.springboot.security.UserDetailsService.service.impl;import java.util.HashSet;import java.util.List;import java.util.Optional;import java.util.Set;import org.springframework.beans.factory.annotation.Autowired;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.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.stereotype.Service;import com.dev.springboot.security.UserDetailsService.model.User;import com.dev.springboot.security.UserDetailsService.repo.UserRepository;import com.dev.springboot.security.UserDetailsService.service.IUserService;@Servicepublic class UserServiceImpl implements IUserService, UserDetailsService{ @Autowired private UserRepository userRepo; @Autowired private BCryptPasswordEncoder passwordEncoder; @Override public Integer saveUser(User user) { String passwd= user.getPassword(); String encodedPasswod = passwordEncoder.encode(passwd); user.setPassword(encodedPasswod); user = userRepo.save(user); return user.getId(); } @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { Optional<User> opt = userRepo.findUserByEmail(email); org.springframework.security.core.userdetails.User springUser=null; if(opt.isEmpty()) { throw new UsernameNotFoundException("User with email: " +email +" not found"); }else { User user =opt.get(); List<String> roles = user.getRoles(); Set<GrantedAuthority> ga = new HashSet<>(); for(String role:roles) { ga.add(new SimpleGrantedAuthority(role)); } springUser = new org.springframework.security.core.userdetails.User( email, user.getPassword(), ga ); } return springUser; } //Other Approach: Using Lambda & Stream API of Java 8 /*@Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { Optional<User> opt = userRepo.findUserByEmail(email); if(opt.isEmpty()) throw new UsernameNotFoundException("User with email: " +email +" not found !"); else { User user = opt.get(); return new org.springframework.security.core.userdetails.User( user.getEmail(), user.getPassword(), user.getRoles() .stream() .map(role-> new SimpleGrantedAuthority(role)) .collect(Collectors.toSet()) ); }*/ } Step#6: Create a UserController class Subsequently, write a controller class for User as ‘UserController.java’ which will control the user registration page. UserController.java package com.dev.springboot.security.UserDetailsService.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.ModelAttribute;import org.springframework.web.bind.annotation.PostMapping;import com.dev.springboot.security.UserDetailsService.model.User;import com.dev.springboot.security.UserDetailsService.service.IUserService;@Controllerpublic class UserController { @Autowired private IUserService userService; // Go to Registration Page @GetMapping("/register") public String register() { return "registerUser"; } // Read Form data to save into DB @PostMapping("/saveUser") public String saveUser( @ModelAttribute User user, Model model ) { Integer id = userService.saveUser(user); String message = "User '"+id+"' saved successfully !"; model.addAttribute("msg", message); return "registerUser"; }} Step#7: Write a Controller class to navigate through pages In spite of UserController, write one more controller class and call it as ‘HomeController.java’. This class will be responsible to navigate through different pages. HomeController.java package com.dev.springboot.security.UserDetailsService.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;@Controllerpublic class HomeController { @GetMapping("/home") public String getHomePage() { return "homePage"; } @GetMapping("/welcome") public String getWelcomePage() { return "welcomePage"; } @GetMapping("/admin") public String getAdminPage() { return "adminPage"; } @GetMapping("/emp") public String getEmployeePage() { return "empPage"; } @GetMapping("/mgr") public String getManagerPage() { return "mgrPage"; } @GetMapping("/hr") public String getHrPage() { return "hrPage"; } @GetMapping("/common") public String getCommonPage() { return "commonPage"; } @GetMapping("/accessDenied") public String getAccessDeniedPage() { return "accessDeniedPage"; }} Step#8: Write UI pages(Thymeleaf) Below are the .html files for UI pages. Place these pages inside ‘src/main/resources/templates’ folder accordingly. registerUser.html <!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head><meta charset="ISO-8859-1"><title>User Registration</title></head><body><h3>User Registration</h3><form action="saveUser" method="post"><pre>Name : <input type="text" name="name"/>Email: <input type="text" name="email"/>Password: <input type="password" name="password"/>Role(s): <input type="checkbox" name="roles" value="Admin"/>Admin <input type="checkbox" name="roles" value="Manager"/>Manager <input type="checkbox" name="roles" value="HR"/>HR <input type="checkbox" name="roles" value="Employee"/>Employee<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/> <input type="submit" value="Register"/></pre></form><div th:text="${msg}"></div></body></html> homePage.html <!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head><meta charset="ISO-8859-1"><title>Insert title here</title></head><body><h3> welcome to the Home Page </h3>This page is accessible to ALL.</body></html> welcomePage.html <!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head><meta charset="ISO-8859-1"><title>Insert title here</title></head><body><h3> Welcome Page after successful Login</h3><a th:href="@{/logout}" >LOGOUT</a></body></html> adminPage.html <!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head><meta charset="ISO-8859-1"><title>Insert title here</title></head><body><h3> Admin Page </h3>Welcome to Admin page.!!!<a th:href="@{/logout}" >LOGOUT</a></body></html> empPage.html <!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head><meta charset="ISO-8859-1"><title>Insert title here</title></head><body><h3> Employee Page </h3><a th:href="@{/logout}" >LOGOUT</a></body></html> mgrPage.html <!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head><meta charset="ISO-8859-1"><title>Insert title here</title></head><body><h3> Manager Page </h3><a th:href="@{/logout}" >LOGOUT</a></body></html> hrPage.html <!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head><meta charset="ISO-8859-1"><title>Insert title here</title></head><body><h3> HR Page </h3><a th:href="@{/logout}" >LOGOUT</a></body></html> commonPage.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="ISO-8859-1"> <title>Insert title here</title> </head> <body> <h3>You are not allowed to access this page. Please go to Welcome Page</h3> <a th:href="@{/welcome}" >Welcome</a> <a th:href="@{/logout}" >LOGOUT</a> </body> </html> accessDeniedPage.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="ISO-8859-1"> <title>Insert title here</title> </head> <body> <h3>You are not allowed to access this page. Please go to Welcome Page</h3> <a th:href="@{/welcome}" >Welcome</a> <a th:href="@{/logout}" >LOGOUT</a> </body> </html> Step#9: Write SecurityConfig class In the end, write the other important class as SecurityConfig.java which will extend a predefined class WebSecurityConfigurerAdapter.java and implement two configure() methods accordingly as given below. SecurityConfig.java package com.dev.springboot.security.UserDetailsService.config;import org.springframework.beans.factory.annotation.Autowired;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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.web.util.matcher.AntPathRequestMatcher;@EnableWebSecurity@Configurationpublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService uds; @Autowired private BCryptPasswordEncoder encoder; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(uds).passwordEncoder(encoder); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/home","/register","/saveUser").permitAll() .antMatchers("/welcome").authenticated() .antMatchers("/admin").hasAuthority("Admin") .antMatchers("/mgr").hasAuthority("Manager") .antMatchers("/emp").hasAuthority("Employee") .antMatchers("/hr").hasAuthority("HR") .antMatchers("/common").hasAnyAuthority("Employeee,Manager,Admin") .anyRequest().authenticated() .and() .formLogin() .defaultSuccessUrl("/welcome",true) .and() .logout() .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .and() .exceptionHandling() .accessDeniedPage("/accessDenied"); }} Step#9A: Write SecurityConfig class Without Using WebSecurityConfigurerAdapter As aforementioned, Spring Security 5.7.0-M2 onward, WebSecurityConfigurerAdapter has been deprecated. Hence, If you are using Spring Security 5.7.0-M2 or later versions, please update your implementation as shown in below code snippet. SecurityConfig.java package com.dev.springboot.security.UserDetailsService.config;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.AuthenticationProvider;import org.springframework.security.authentication.dao.DaoAuthenticationProvider;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.web.SecurityFilterChain;import org.springframework.security.web.util.matcher.AntPathRequestMatcher;@EnableWebSecurity@Configurationpublic class SecurityConfig { @Autowired private UserDetailsService uds; @Autowired private BCryptPasswordEncoder encoder; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests() .requestMatchers("/home","/register","/saveUser").permitAll() .requestMatchers("/welcome").authenticated() .requestMatchers("/admin").hasAuthority("Admin") .requestMatchers("/mgr").hasAuthority("Manager") .requestMatchers("/emp").hasAuthority("Employee") .requestMatchers("/hr").hasAuthority("HR") .requestMatchers("/common").hasAnyAuthority("Employeee,Manager,Admin") .anyRequest().authenticated() .and() .formLogin() .defaultSuccessUrl("/welcome",true) .and() .logout() .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .and() .exceptionHandling() .accessDeniedPage("/accessDenied") .and() .authenticationProvider(authenticationProvider()); return http.build(); } @Bean public AuthenticationProvider authenticationProvider() { DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); authenticationProvider.setUserDetailsService(uds); authenticationProvider.setPasswordEncoder(encoder); return authenticationProvider; }} Finally we have completed the coding part. How to test the security enabled Application ? Although the word ‘testing’ looks very easy to a developer, but it is equally important as it provides the result of our implementation on the whole. While testing the application you should keep configure(HttpSecurity http) method of SecurityConfig class in front of you, then follow the steps given below: 1) Start the application : Right click on the project, then select “Run As’ >> ‘Spring Boot App’. 2) Enter the registration page URL http://localhost:8080/register, then check if it is accessible to every one without even login to the application. 3) Enter the required field values and complete the registration process by clicking on the ‘Register’ button accordingly. 4) Now Enter any URL specific to the role you selected in registration. Suppose you entered URL http://localhost:8080/admin, then it should redirect you to the in-built Login page. 5) Enter the credentials(email id in place of username) and Login to the application. It will redirect you to the default success URL which is welcome page. 6) Now enter the URL http://localhost:8080/admin again, this time you will be able to access the admin page. 7) Repeat the above steps for other roles as well. Additionally, as mentioned above keep the code in front of you and test each scenario subsequently. Summary After going through all the theoretical & examples part of ‘How to implement Spring Boot Thymeleaf Security Login Example using UserDetailsService?’, finally, we are able to implement web security in a Spring Boot project. Of course, In this article we have covered the third way of implementing security feature. Similarly, we will talk about some more ways of security like REST security in our upcoming articles. If there is any change in the future, we will update the same accordingly. If you want to learn more about Spring Security, kindly visit spring.io documentation. Moreover, Feel free to provide your comments in the comments section. Related
This is really interesting, You’re a very skilled blogger. I’ve joined your rss feed and look forward to seeking more of your excellent post. Also, I have shared your web site in my social networks! Reply
Thanks for your motivation to do better in future posts as well. Also, Thanks for sharing the web site. Reply
Heya are using WordPress for your site platform? I’m new to the blog world but I’m trying to get started and create my own. Do you need any html coding expertise to make your own blog? Any help would be really appreciated! Reply
Request you to please put your comments which are related to the topic so that other readers also get benefitted. Topic is not related to ‘How to make your own blog?’ at all. Reply
Nicely explained. You start your articles with basics that is even the best thing for readers to make the concepts stronger. Reply
I liked the way you explain the concepts, from basic to advanced…..Looking forward to check your upcoming posts. Reply
Hi there! Someone in my Facebook group shared this site with us so I came to take a look. I’m definitely loving the information. I’m bookmarking and will be tweeting this to my followers! Fantastic blog and superb style and design. Reply
Hello There. I found your weblog using msn. That is a very well written article. I will make sure to bookmark it and come back to read more of your helpful info. Thank you for the post. I’ll definitely return. Reply
You completed a number of fine points there. I did a search on the topic and found most folks will go along with with your blog. Reply
Hey there, I seriously like your amazing internet site! This is a nice posting. My family and i look forward to reading more exciting information in which youll be publishing within the forthcoming. We’ve found out a lot by this. Thanks a ton. -Olene Griffins Reply
I believe this is one of the most significant info for me. And i am glad studying your article. However wanna observation on some general things, The web site style is perfect, the articles is in point of fact nice : D. Excellent process, cheers Reply
Hey , very nice explanation . after reading and watching multiple articles. I can say this is one of the finest explanation with diagrams ,theory and codes. Hat’s off Reply
Thanks everyone for all your valuable feedback. It will motivate us to do even better in future articles. Now the code is updated as per the changes in Spring Security 5.7.0-M2 API i.e. Without Using WebSecurityConfigurerAdapter. Reply