Spring boot Login/ Registration with example
by Mayank K. mayankseoCreating a Login Registration Application in Spring Boot. Spring Boot is a module of spring framework that provides Rapid Application Development. It allows you to create stand-alone, production-grade Spring based Applications that you can "just run". In this tutorial, I am going create simple Registration and Login functionality with Spring Boot, Spring Security, Spring Data JPA, and HSQL. Let's move step by step.
Prerequisites
- JDK 1.7 or later
- Maven 3 or later
Stacks Used in Project
- Spring Security
- Spring Boot
- Spring Data
- JPA
- JSP
Project Structure
├── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── springbootapp
│ │ └── auth
│ │ ├── model
│ │ │ ├── Role.java
│ │ │ └── User.java
│ │ ├── repository
│ │ │ ├── RoleRepository.java
│ │ │ └── UserRepository.java
│ │ ├── service
│ │ │ ├── SecurityServiceImpl.java
│ │ │ ├── SecurityService.java
│ │ │ ├── UserDetailsServiceImpl.java
│ │ │ ├── UserServiceImpl.java
│ │ │ └── UserService.java
│ │ ├── validator
│ │ │ └── UserValidator.java
│ │ ├── web
│ │ │ └── UserController.java
│ │ ├── WebApplication.java
│ │ └── WebSecurityConfig.java
│ ├── resources
│ │ ├── application.properties
│ │ └── validation.properties
│ └── webapp
│ ├── resources
│ │ ├── css
│ │ │ ├── bootstrap.min.css
│ │ │ └── common.css
│ │ └── js
│ │ └── bootstrap.min.js
│ ├── login.jsp
│ ├── registration.jsp
│ └── welcome.jsp
└── pom.xml
Dependencies of Project pom.xml
<?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> <artifactId>auth</artifactId> <name>auth</name> <description>auth</description> <packaging>war</packaging> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.5.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.7</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-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Defining JPA Entities
In spring you can define JPA Entity with @Entity annotation,which represent a table in your database.
Creating our User Model
Create a new file named User.java in src/main/java/com/springbootapp/auth/model/ directory and add following lines of code.
package com.springbootapp.auth.model; import javax.persistence.*; import java.util.Set; @Entity @Table(name = "user") public class User { private Long id; private String username; private String password; private String passwordConfirm; private Set roles; @Id @GeneratedValue(strategy = GenerationType.AUTO) public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Transient public String getPasswordConfirm() { return passwordConfirm; } public void setPasswordConfirm(String passwordConfirm) { this.passwordConfirm = passwordConfirm; } @ManyToMany @JoinTable(name = "user_role",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")) public Set getRoles() { return roles; } public void setRoles(Set roles) { this.roles = roles; } }
Create another file named Role.java in src/main/java/com/springbootapp/auth/model/
package com.springbootapp.auth.model; import javax.persistence.*; import java.util.Set; @Entity @Table(name = "role") public class Role { private Long id; private String name; private Set users; @Id @GeneratedValue(strategy = GenerationType.AUTO) 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; } @ManyToMany(mappedBy = "roles") public Set getUsers() { return users; } public void setUsers(Set users) { this.users = users; } }
Working with Spring Data JPA Repositories
This contains some pre-built Repository implemented to perform common tasks with the database like finding, saving, updating records. records: findOne, findAll, save..
Create a new file named UserRepository.java in src/main/java/com/springbootapp/auth/repository/ add following code in it.
package com.springbootapp.auth.repository; import com.springbootapp.auth.model.User; import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository{ User findByUsername(String username); }
Create another file RoleRepository.java in src/main/java/com/springbootapp/auth/repository/ and add follwing line on code.
package com.springbootapp.auth.repository; import com.springbootapp.auth.model.Role; import org.springframework.data.jpa.repository.JpaRepository; public interface RoleRepository extends JpaRepository{ }
Implementing Spring Security's
To implement login/authentication with Spring Security, we need to implement org.springframework.security.core.userdetails.UserDetailsService interface,so create an new file named UserDetailsServiceImpl.java in src/main/java/com/springbootapp/auth/service/ directory add following code in it.
Suggested Read: Best Interview Questions on Spring Boot
package com.springbootapp.auth.service; import com.springbootapp.auth.model.Role; import com.springbootapp.auth.model.User; import com.springbootapp.auth.repository.UserRepository; 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.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.HashSet; import java.util.Set; @Service public class UserDetailsServiceImpl implements UserDetailsService{ @Autowired private UserRepository userRepository; @Override @Transactional(readOnly = true) public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException { User user = userRepository.findByUsername(username); Set grantedAuthorities = new HashSet<>(); for (Role role : user.getRoles()){ grantedAuthorities.add(new SimpleGrantedAuthority(role.getName())); } return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(), grantedAuthorities); } }
Security Service
Next, We are going to create SecurityService that provides functionality to current loggedIn user and auto login user after registering an account.
Create a new file SecurityServiceImpl.java in src/main/java/com/springbootapp/auth/service/ directory and add the follwing line of code
package com.springbootapp.auth.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Service; @Service public class SecurityServiceImpl implements SecurityService{ @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; private static final Logger logger = LoggerFactory.getLogger
(SecurityServiceImpl.class); @Override public String findLoggedInUsername() { Object userDetails = SecurityContextHolder.getContext().getAuthentication().getDetails(); if (userDetails instanceof UserDetails) { return ((UserDetails)userDetails).getUsername(); } return null; } @Override public void autologin(String username, String password) { UserDetails userDetails = userDetailsService.loadUserByUsername(username); UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken
= new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities()); authenticationManager.authenticate(usernamePasswordAuthenticationToken); if (usernamePasswordAuthenticationToken.isAuthenticated()) { SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); logger.debug(String.format("Auto login %s successfully!", username)); } } }
User Service
Create a new file UserServiceImpl.java in src/main/java/com/springbootapp/auth/service/ directory. This file provides service service for registering an account.
package com.springbootapp.auth.service; import com.springbootapp.auth.model.User; import com.springbootapp.auth.repository.RoleRepository; import com.springbootapp.auth.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import java.util.HashSet; @Service public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; @Autowired private RoleRepository roleRepository; @Autowired private BCryptPasswordEncoder bCryptPasswordEncoder; @Override public void save(User user) { user.setPassword(bCryptPasswordEncoder.encode(user.getPassword())); user.setRoles(new HashSet<>(roleRepository.findAll())); userRepository.save(user); } @Override public User findByUsername(String username) { return userRepository.findByUsername(username); } }
Adding Spring validator
Implement org.springframework.validation.Validator to provide validation to our registration controller.
Create a file name UserValidator.java in src/main/java/com/springbootapp/auth/validator/ directory and add following code.
package com.springbootapp.auth.validator; import com.springbootapp.auth.model.User; import com.springbootapp.auth.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.validation.Errors; import org.springframework.validation.ValidationUtils; import org.springframework.validation.Validator; @Component public class UserValidator implements Validator { @Autowired private UserService userService; @Override public boolean supports(Class aClass) { return User.class.equals(aClass); } @Override public void validate(Object o, Errors errors) { User user = (User) o; ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username", "NotEmpty"); if (user.getUsername().length() < 6 || user.getUsername().length() > 32) { errors.rejectValue("username", "Size.userForm.username"); } if (userService.findByUsername(user.getUsername()) != null) { errors.rejectValue("username", "Duplicate.userForm.username"); } ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "NotEmpty"); if (user.getPassword().length() < 8 || user.getPassword().length() > 32) { errors.rejectValue("password", "Size.userForm.password"); } if (!user.getPasswordConfirm().equals(user.getPassword())) { errors.rejectValue("passwordConfirm", "Diff.userForm.passwordConfirm"); } } }
Creating our controller for login and registration.
This controller is responsible for authenticating/ registering users. Create a new file UserController.java in src/main/java/com/springbootapp/auth/web/ and add follwing code.
package com.springbootapp.auth.web; import com.springbootapp.auth.model.User; import com.springbootapp.auth.service.SecurityService; import com.springbootapp.auth.service.UserService; import com.springbootapp.auth.validator.UserValidator; 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.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class UserController { @Autowired private UserService userService; @Autowired private SecurityService securityService; @Autowired private UserValidator userValidator; @RequestMapping(value = "/registration", method = RequestMethod.GET) public String registration(Model model) { model.addAttribute("userForm", new User()); return "registration"; } @RequestMapping(value = "/registration", method = RequestMethod.POST) public String registration(@ModelAttribute("userForm") User userForm,
BindingResult bindingResult, Model model) { userValidator.validate(userForm, bindingResult); if (bindingResult.hasErrors()) { return "registration"; } userService.save(userForm); securityService.autologin(userForm.getUsername(), userForm.getPasswordConfirm()); return "redirect:/welcome"; } @RequestMapping(value = "/login", method = RequestMethod.GET) public String login(Model model, String error, String logout) { if (error != null) model.addAttribute("error", "Your username and password is invalid."); if (logout != null) model.addAttribute("message", "You have been logged out successfully."); return "login"; } @RequestMapping(value = {"/", "/welcome"}, method = RequestMethod.GET) public String welcome(Model model) { return "welcome"; } }
Managing our Application Properties
Add following code in src/main/resources/application.properties file
spring.mvc.view.prefix: / spring.mvc.view.suffix: .jsp spring.jpa.hibernate.ddl-auto=create spring.jpa.show-sql=true spring.messages.basename=validation
Add following code in src/main/resources/validation.properties file
NotEmpty=This field is required. Size.userForm.username=Please use between 6 and 32 characters. Duplicate.userForm.username=Someone already has that username. Size.userForm.password=Try one with at least 8 characters. Diff.userForm.passwordConfirm=These passwords don't match.
Managing Web Security Configuration
Add following lines of code in src/main/java/com/springbootapp/auth/WebSecurityConfig.java
package com.springbootapp.auth; 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.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/resources/**", "/registration").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .permitAll(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); } }
Application Configuration
Add following lines of code in src/main/java/com/springbootapp/auth/WebApplication.java
package com.springbootapp.auth; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.web.SpringBootServletInitializer; @SpringBootApplication public class WebApplication extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplircationBuilder application) { return application.sources(WebApplication.class); } public static void main(String[] args) throws Exception { SpringApplication.run(WebApplication.class, args); } }
Running the applications
Run the application using mvn clean spring-boot:run and visit to http://localhost:8080
Conclusion
After reading this article you are now able to create a simple login and registration application in Spring Boot.
References
https://www.youtube.com/watch?v=7Vp6iXmO30ESponsor Ads
Created on Jan 29th 2019 03:50. Viewed 516 times.