Spring Boot Security using Database


This post walks you through the process of creating a simple registration and login example with Spring Security using database. Please read this previous post before conitnue with this information. First we need to add Spring Data JPA dependency to the build.gradle

compile 'org.springframework.boot:spring-boot-starter-data-jpa'

Then we need to change Spring security Java config class in order to add userDetailsService to implement database access functionality:

package com.jos.dem.springboot.security.config

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Configuration
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
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.config.annotation.web.configuration.EnableWebSecurity

@Configuration
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  UserDetailsService userDetailsService

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
    .authorizeRequests()
    .antMatchers("/assets/**").permitAll()
    .anyRequest().authenticated()
    .and()
    .formLogin()
    .loginPage("/login")
    .permitAll()
  }

  @Autowired
  void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth
    .userDetailsService(userDetailsService)
    .passwordEncoder(new BCryptPasswordEncoder())
  }

}

This is the userDetailsService implementation

package com.jos.dem.springboot.security.service.impl

import org.springframework.stereotype.Service
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.userdetails.UsernameNotFoundException

import  com.jos.dem.springboot.security.model.User
import  com.jos.dem.springboot.security.repository.UserRepository

@Service
class UserDetailsServiceImpl implements UserDetailsService {

  @Autowired
  UserRepository userRepository

  @Override
  org.springframework.security.core.userdetails.User loadUserByUsername(String username) throws UsernameNotFoundException {
    User user = userRepostory.findByUsername(username)
    Set<GrantedAuthority> grantedAuthorities = [] as Set
    grantedAuthorities << new SimpleGrantedAuthority(user.role.toString())
    new org.springframework.security.core.userdetails.User(user.username, user.password, grantedAuthorities)
  }

}

JPA Entity is defined with @Entity annotation to represent a table in your database, this is the User entity to represent an user with credentials.

package com.jos.dem.springboot.security.model

import static javax.persistence.EnumType.STRING
import static javax.persistence.GenerationType.AUTO

import javax.persistence.Id
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Enumerated
import javax.persistence.GeneratedValue

@Entity
class User {

  @Id
  @GeneratedValue(strategy=AUTO)
  Long id
  @Column(unique = true, nullable = false)
  String username
  @Column(nullable = false)
  String password
  @Column(nullable = true)
  String firstname
  @Column(nullable = true)
  String lastname
  @Column(nullable = true)
  String email
  @Column(nullable = false)
  @Enumerated(STRING)
  Role role
  @Column(nullable = false)
  Boolean enabled = false
  @Column(nullable = false)
  Date dateCreate = new Date()

}

Any user in the system has a Role

package com.jos.dem.springboot.security.model

enum Role {
  USER,ADMIN
}

This is our UserRepository to find a user in a dabatabase by username and save a new user.

package com.jos.dem.springboot.security.repository

import com.jos.dem.springboot.security.model.User
import org.springframework.data.jpa.repository.JpaRepository

interface UserRepository extends JpaRepository<User,Long> {

  User findByUsername(String username)
  User save(User user)

}

Finally we are going to create a default user in our database with encrypted password, in order to do that we are going to implement ApplicationReadyEvent in a Bootstrap class, that’s it, when Spring Boot is up and running we are going to verify if a default user exist in our database otherwise is going to create it.

package com.jos.dem.springboot.security.config

import org.springframework.stereotype.Component
import org.springframework.context.ApplicationListener
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.context.event.ApplicationReadyEvent
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder

import com.jos.dem.springboot.security.model.User
import com.jos.dem.springboot.security.model.Role
import com.jos.dem.springboot.security.repository.UserRepository

import org.slf4j.Logger
import org.slf4j.LoggerFactory

@Component
class Boostrap implements ApplicationListener<ApplicationReadyEvent>{

  @Autowired
  UserRepository userRepository

  Logger log = LoggerFactory.getLogger(this.class)

  @Override
  void onApplicationEvent(final ApplicationReadyEvent event) {
    log.info 'Verifying if default user exist'
    createUserWithRole('josdem', '12345678', 'joseluis.delacruz@gmail.com', Role.USER)
  }

  private createUserWithRole(String username, String password, String email, Role authority){
    if(!userRepository.findByUsername(username)){
      User user = new User(
        username:username,
        password:new BCryptPasswordEncoder().encode(password),
        email:email,
        role:authority,
        firstname:username,
        lastname:username,
        enabled:true
      )
      userRepository.save(user)
    }
  }

}

Do not forget to create your application.properties file, so you can specify your local database credentials there.

spring.datasource.url=jdbc:mysql://localhost/spring_boot_security
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.generate-ddl=true

spring.messages.basename=i18n/messages

To browse the project go here, to download the project:

git clone https://github.com/josdem/spring-boot-security.git
git fetch
git checkout feature/database

To run the project:

gradle bootRun

Return to the main article