In the previous article, we have learned Spring Boot + Spring MVC + Role Based Spring Security + JPA + Thymeleaf + MySQL Tutorial
What we’ll build?
1. Register user (stored data into MySQL database).
2. Login Authentication - validate user login credentials with database email and password.
Tools and Technologies Used
- Spring Boot - 2.0.4.RELEASE
- JDK - 1.8 or later
- Spring Framework - 5.0.8 RELEASE
- Hibernate - 5.2.17. Final
- Maven - 3.2+
- IDE - Eclipse or Spring Tool Suite (STS)
- Tomcat - 8.5+
- Thymeleaf - 3.0.9 RELEASE
- Bootstrap - 3.3.7
- JQuery - 3.2.1
- MySQL - 5.1.46
Creating and Importing a Project
Enter below details in Spring Initializr:
Project Name: registration-login-springboot-security-thymeleaf
Project Type: Maven
Choose dependencies: Web, JPA, MySQL, Thymeleaf, Security
Package name: net.javaguides.springboot.springsecurity
Project Structure
The pom.xml File - Maven Dependencies
Here is a complete 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.guides.springboot</groupId>
<artifactId>registration-login-springboot-security-thymeleaf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>registration-login-springboot-security-thymeleaf</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<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.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<!-- bootstrap and jquery -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.7</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.2.1</version>
</dependency>
<!-- mysql connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Spring Security Configuration
package net.javaguides.springboot.springsecurity.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.dao.DaoAuthenticationProvider;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import net.javaguides.springboot.springsecurity.service.UserService;
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(
"/registration**",
"/js/**",
"/css/**",
"/img/**",
"/webjars/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.permitAll();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder());
return auth;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
}
Configure MySQL and View Resolver
Spring Boot tries to auto-configure a DataSource if spring-data-jpa dependency is in the classpath by reading the database configuration from the application.properties file.
So, we just have to add the configuration, and Spring Boot will take care of the rest.
Open the application.properties file and add the following properties to it.
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/registration_module?useSSL=false
spring.datasource.username = root
spring.datasource.password = root
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
You will need to create a database named demo in MySQL, and change the spring.datasource.username & spring.datasource.password properties as per your MySQL installation.
In the above properties file, the last two properties are for Hibernate. Spring Boot uses Hibernate as the default JPA implementation.
The property spring.jpa.hibernate.ddl-auto is used for database initialization. I’ve used the value “update” for this property.
Database Create SQL Scripts
As we specified spring.jpa.hibernate.ddl-auto = update property will auto-create tables in MySQL database. The below are create statements of three tables.
CREATE TABLE `role` (
`id` bigint(20) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL,
`email` varchar(255) DEFAULT NULL,
`first_name` varchar(255) DEFAULT NULL,
`last_name` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UKob8kqyqqgmefl0aco34akdtpe` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `users_roles` (
`user_id` bigint(20) NOT NULL,
`role_id` bigint(20) NOT NULL,
KEY `FKt4v0rrweyk393bdgt107vdx0x` (`role_id`),
KEY `FKgd3iendaoyh04b95ykqise6qh` (`user_id`),
CONSTRAINT `FKgd3iendaoyh04b95ykqise6qh` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
CONSTRAINT `FKt4v0rrweyk393bdgt107vdx0x` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
Spring Rest Controller - UserRegistrationController.java
package net.javaguides.springboot.springsecurity.web;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import net.javaguides.springboot.springsecurity.model.User;
import net.javaguides.springboot.springsecurity.service.UserService;
import net.javaguides.springboot.springsecurity.web.dto.UserRegistrationDto;
@Controller
@RequestMapping("/registration")
public class UserRegistrationController {
@Autowired
private UserService userService;
@ModelAttribute("user")
public UserRegistrationDto userRegistrationDto() {
return new UserRegistrationDto();
}
@GetMapping
public String showRegistrationForm(Model model) {
return "registration";
}
@PostMapping
public String registerUserAccount(@ModelAttribute("user") @Valid UserRegistrationDto userDto,
BindingResult result) {
User existing = userService.findByEmail(userDto.getEmail());
if (existing != null) {
result.rejectValue("email", null, "There is already an account registered with that email");
}
if (result.hasErrors()) {
return "registration";
}
userService.save(userDto);
return "redirect:/registration?success";
}
}
Spring Rest Controller - MainController.java
package net.javaguides.springboot.springsecurity.web;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MainController {
@GetMapping("/")
public String root() {
return "index";
}
@GetMapping("/login")
public String login(Model model) {
return "login";
}
@GetMapping("/user")
public String userIndex() {
return "user/index";
}
}
Data Transfer Object - UserRegistrationDto.java
package net.javaguides.springboot.springsecurity.web.dto;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import net.javaguides.springboot.springsecurity.constraint.FieldMatch;
@FieldMatch.List({
@FieldMatch(first = "password", second = "confirmPassword", message = "The password fields must match"),
@FieldMatch(first = "email", second = "confirmEmail", message = "The email fields must match")
})
public class UserRegistrationDto {
@NotEmpty
private String firstName;
@NotEmpty
private String lastName;
@NotEmpty
private String password;
@NotEmpty
private String confirmPassword;
@Email
@NotEmpty
private String email;
@Email
@NotEmpty
private String confirmEmail;
@AssertTrue
private Boolean terms;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getConfirmEmail() {
return confirmEmail;
}
public void setConfirmEmail(String confirmEmail) {
this.confirmEmail = confirmEmail;
}
public Boolean getTerms() {
return terms;
}
public void setTerms(Boolean terms) {
this.terms = terms;
}
}
Creating Field Matching Validator
package net.javaguides.springboot.springsecurity.constraint;
import javax.validation.Payload;
import javax.validation.Constraint;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({
TYPE,
ANNOTATION_TYPE
})
@Retention(RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
@Documented
public @interface FieldMatch {
String message() default "{constraints.field-match}";
Class << ? > [] groups() default {};
Class << ? extends Payload > [] payload() default {};
String first();
String second();
@Target({
TYPE,
ANNOTATION_TYPE
})
@Retention(RUNTIME)
@Documented
@interface List {
FieldMatch[] value();
}
}
package net.javaguides.springboot.springsecurity.constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.apache.commons.beanutils.BeanUtils;
public class FieldMatchValidator implements ConstraintValidator < FieldMatch, Object > {
private String firstFieldName;
private String secondFieldName;
@Override
public void initialize(final FieldMatch constraintAnnotation) {
firstFieldName = constraintAnnotation.first();
secondFieldName = constraintAnnotation.second();
}
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context) {
try {
final Object firstObj = BeanUtils.getProperty(value, firstFieldName);
final Object secondObj = BeanUtils.getProperty(value, secondFieldName);
return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);
} catch (final Exception ignore) {}
return true;
}
}
Service Layer - UserService.java
package net.javaguides.springboot.springsecurity.service;
import org.springframework.security.core.userdetails.UserDetailsService;
import net.javaguides.springboot.springsecurity.model.User;
import net.javaguides.springboot.springsecurity.web.dto.UserRegistrationDto;
public interface UserService extends UserDetailsService {
User findByEmail(String email);
User save(UserRegistrationDto registration);
}
Service Layer - UserServiceImpl.java
package net.javaguides.springboot.springsecurity.service;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
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.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import net.javaguides.springboot.springsecurity.model.Role;
import net.javaguides.springboot.springsecurity.model.User;
import net.javaguides.springboot.springsecurity.repository.UserRepository;
import net.javaguides.springboot.springsecurity.web.dto.UserRegistrationDto;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
public User findByEmail(String email) {
return userRepository.findByEmail(email);
}
public User save(UserRegistrationDto registration) {
User user = new User();
user.setFirstName(registration.getFirstName());
user.setLastName(registration.getLastName());
user.setEmail(registration.getEmail());
user.setPassword(passwordEncoder.encode(registration.getPassword()));
user.setRoles(Arrays.asList(new Role("ROLE_USER")));
return userRepository.save(user);
}
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email);
if (user == null) {
throw new UsernameNotFoundException("Invalid username or password.");
}
return new org.springframework.security.core.userdetails.User(user.getEmail(),
user.getPassword(),
mapRolesToAuthorities(user.getRoles()));
}
private Collection << ? extends GrantedAuthority > mapRolesToAuthorities(Collection < Role > roles) {
return roles.stream()
.map(role - > new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
}
}
Spring Data Repository - UserRepository.java
package net.javaguides.springboot.springsecurity.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.javaguides.springboot.springsecurity.model.User;
@Repository
public interface UserRepository extends JpaRepository < User, Long > {
User findByEmail(String email);
}
Create JPA Entities
PA entity - User.java
package net.javaguides.springboot.springsecurity.model;
import javax.persistence.*;
import java.util.Collection;
@Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = "email"))
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private String email;
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 Collection < Role > roles;
public User() {}
public User(String firstName, String lastName, String email, String password) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
}
public User(String firstName, String lastName, String email, String password, Collection < Role > roles) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
this.roles = roles;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Collection < Role > getRoles() {
return roles;
}
public void setRoles(Collection < Role > roles) {
this.roles = roles;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", password='" + "*********" + '\'' +
", roles=" + roles +
'}';
}
}
JPA entity - Role.java
package net.javaguides.springboot.springsecurity.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
public Role() {}
public Role(String name) {
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Thyemeleaf Templates
User Registration Page
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css"
th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css}" />
<title>Registration</title>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#navbar" aria-expanded="false"
aria-controls="navbar">
<span class="sr-only">Toggle navigation</span> <span
class="icon-bar"></span> <span class="icon-bar"></span> <span
class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#" th:href="@{/}">Registration and
Login Module</a>
</div>
</div>
</nav>
<br>
<br>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div th:if="${param.success}">
<div class="alert alert-info">You've successfully registered
to our awesome app!</div>
</div>
<h1>Registration</h1>
<form th:action="@{/registration}" th:object="${user}" method="post">
<p class="error-message" th:if="${#fields.hasGlobalErrors()}"
th:each="error : ${#fields.errors('global')}" th:text="${error}">Validation
error</p>
<div class="form-group"
th:classappend="${#fields.hasErrors('firstName')}? 'has-error':''">
<label for="firstName" class="control-label">First name</label> <input
id="firstName" class="form-control" th:field="*{firstName}" />
<p class="error-message"
th:each="error: ${#fields.errors('firstName')}"
th:text="${error}">Validation error</p>
</div>
<div class="form-group"
th:classappend="${#fields.hasErrors('lastName')}? 'has-error':''">
<label for="lastName" class="control-label">Last name</label> <input
id="lastName" class="form-control" th:field="*{lastName}" />
<p class="error-message"
th:each="error : ${#fields.errors('lastName')}"
th:text="${error}">Validation error</p>
</div>
<div class="form-group"
th:classappend="${#fields.hasErrors('email')}? 'has-error':''">
<label for="email" class="control-label">E-mail</label> <input
id="email" class="form-control" th:field="*{email}" />
<p class="error-message"
th:each="error : ${#fields.errors('email')}" th:text="${error}">Validation
error</p>
</div>
<div class="form-group"
th:classappend="${#fields.hasErrors('confirmEmail')}? 'has-error':''">
<label for="confirmEmail" class="control-label">Confirm
e-mail</label> <input id="confirmEmail" class="form-control"
th:field="*{confirmEmail}" />
<p class="error-message"
th:each="error : ${#fields.errors('confirmEmail')}"
th:text="${error}">Validation error</p>
</div>
<div class="form-group"
th:classappend="${#fields.hasErrors('password')}? 'has-error':''">
<label for="password" class="control-label">Password</label> <input
id="password" class="form-control" type="password"
th:field="*{password}" />
<p class="error-message"
th:each="error : ${#fields.errors('password')}"
th:text="${error}">Validation error</p>
</div>
<div class="form-group"
th:classappend="${#fields.hasErrors('confirmPassword')}? 'has-error':''">
<label for="confirmPassword" class="control-label">Confirm
password</label> <input id="confirmPassword" class="form-control"
type="password" th:field="*{confirmPassword}" />
<p class="error-message"
th:each="error : ${#fields.errors('confirmPassword')}"
th:text="${error}">Validation error</p>
</div>
<div class="form-group"
th:classappend="${#fields.hasErrors('terms')}? 'has-error':''">
<input id="terms" type="checkbox" th:field="*{terms}" /> <label
class="control-label" for="terms"> I agree with the <a
href="#">terms and conditions</a> for Registration.
</label>
<p class="error-message"
th:each="error : ${#fields.errors('terms')}" th:text="${error}">Validation
error</p>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Register</button>
<span>Already registered? <a href="/" th:href="@{/login}">Login
here</a></span>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript"
th:src="@{/webjars/jquery/3.2.1/jquery.min.js/}"></script>
<script type="text/javascript"
th:src="@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}"></script>
</body>
</html>
Index Page
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css"
th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css}" />
<title>Registration</title>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#navbar" aria-expanded="false"
aria-controls="navbar">
<span class="sr-only">Toggle navigation</span> <span
class="icon-bar"></span> <span class="icon-bar"></span> <span
class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#" th:href="@{/}">Registration and
Login Module</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li sec:authorize="isAuthenticated()"><a th:href="@{/logout}">Logout</a></li>
</ul>
</div>
</div>
</nav>
<br>
<br>
<div class="container">
<h2>User Registration and Login Module using Spring Boot, Spring
MVC, Spring Security, JPA/Hibernate and Thymeleaf</h2>
<p>
Welcome <span sec:authentication="principal.username">User</span>
</p>
</div>
<script type="text/javascript"
th:src="@{/webjars/jquery/3.2.1/jquery.min.js/}"></script>
<script type="text/javascript"
th:src="@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}"></script>
</body>
</html>
Login Page
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css"
th:href="@{/webjars/bootstrap/3.3.7/css/bootstrap.min.css}" />
<title>Registration</title>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#navbar" aria-expanded="false"
aria-controls="navbar">
<span class="sr-only">Toggle navigation</span> <span
class="icon-bar"></span> <span class="icon-bar"></span> <span
class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#" th:href="@{/}">Registration and
Login Module</a>
</div>
</div>
</nav>
<br>
<br>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1>Login page</h1>
<form th:action="@{/login}" method="post">
<div th:if="${param.error}">
<div class="alert alert-danger">Invalid username or
password.</div>
</div>
<div th:if="${param.logout}">
<div class="alert alert-info">You have been logged out.</div>
</div>
<div class="form-group">
<label for="username">Username</label>: <input type="text"
id="username" name="username" class="form-control"
autofocus="autofocus" placeholder="Username" />
</div>
<div class="form-group">
<label for="password">Password</label>: <input type="password"
id="password" name="password" class="form-control"
placeholder="Password" />
</div>
<div class="form-group">
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<input type="submit" name="login-submit" id="login-submit"
class="form-control btn btn-primary" value="Log In" />
</div>
</div>
</div>
<div class="form-group">
<span>New user? <a href="/" th:href="@{/registration}">Register
here</a></span>
</div>
</form>
</div>
</div>
</div>
<script type="text/javascript"
th:src="@{/webjars/jquery/3.2.1/jquery.min.js/}"></script>
<script type="text/javascript"
th:src="@{/webjars/bootstrap/3.3.7/js/bootstrap.min.js}"></script>
</body>
</html>
Spring Boot Application Running
We use spring boot to start our application.package net.javaguides.springboot.springsecurity;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
package net.javaguides.springboot.springsecurity;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The application will start at Spring Boot’s default tomcat port 8080.
Demo
Registration page demo
Login page demo
Reference
Learn complete Spring boot on Spring Boot Tutorial
Source code on GitHub
The source code of this article available on my GitHub repository registration-login-springboot-security-thymeleaf
what is username login ? I used email but not success
ReplyDeleteFirst register to the application and then use registered email and password to login. If this don't work then there may be issue in your code set up.
Delete