Articles

Spring boot Login/ Registration with example

by Mayank K. mayankseo

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

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

Sponsor Ads


About Mayank K. Advanced   mayankseo

177 connections, 2 recommendations, 400 honor points.
Joined APSense since, October 23rd, 2018, From DELHI, India.

Created on Jan 29th 2019 03:50. Viewed 516 times.

Comments

No comment, be the first to comment.
Please sign in before you comment.