loading...

User Account Login/Registration feature with Spring Boot

onlineinterview profile image Mayank K. Chaurasiya Updated on ・9 min read

Creating 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 to 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

Spring boot Interview Questions
Spring boot interview Questions

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://hellokoding.com/registration-and-login-example-with-spring-security-spring-boot-spring-data-jpa-hsql-jsp/
Basic Spring Boot Interview Questions

https://www.youtube.com/watch?v=7Vp6iXmO30E

Discussion

pic
Editor guide
Collapse
philippejefferson profile image
Philippe-Jefferson

I used your script but I can not implement SecurityService. Caan you help me?

Collapse
akbarramzan profile image
AkbarRamzan

I have the same problem and I am struggling to find a solution.

Collapse
deaadend profile image
deaadend

hellokoding.com/registration-and-l...

This user forgot to implement the SecurityService class, its in this site!

Collapse
gamyuen_braday profile image
Braday

Is the Repository equivalent to DAO and Service also know as helper class? Thanks.

Collapse
philippejefferson profile image
Philippe-Jefferson

Hello,
I would like to encrypt the passwords of my users and check an account from an email and provide send a verification link by mail you can help me?

Collapse
maverickmarmot profile image
Amal

I would like to integrate this feature on my website. thanks.
slackchannels.com/cogeco-outages/