How to do user authentication in Spring Boot using PostgreSQL database?

Let’s say you want to create an application in Spring Boot and authenticate the users who use it against credentials stored in a PostgreSQL database.

Below are the high level steps to implement it in Spring Boot:

  • Create a spring boot project with authentication related dependencies.
  • Add the database configuration in application.properties against which you want to authenticate.
  • Create an entity class named User which will represent the table containing the credentials.
  • Create a repository to access the above created table.
  • Create a service (UserDetailsService) to access the above repository and fetch user details.
  • Configure authenticated related configuration in a configuration class ( by extending WebSecurityConfigurationAdapter)
  • Create users in the database.
  • Create an index.html file to land the user when they login.

That’s it!

Now let’s dive into the details:

STEP1: Create a spring boot project with authenticated related dependencies

I created one using spring initializr and added the below dependencies:

	        <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.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	        <dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>

spring-boot-starter-data-jpa dependency is used to access database, against which you are going to validate

spring-boot-starter-security is for authentication

spring-boot-starter-web is for packaging the web application and accessing it over http

org.postgresql is for configuring PostgreSQL database

STEP 2 : Add database properties in application.properties file

Below are the properties required for configuring a PostGreSQL database

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=create
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=

The first time you run your application set spring.jpa.hibernate.ddl-auto=create so that Spring Boot will generate the User table for us (where we are going to store user credentials)

After the first run , change it to “update”

STEP 3: Create the User Entity class

Spring Security requires us to create an entity object which implements UserDetails interface provided by Spring Security.

Here is a sample implementation:

package com.springboot.dbauthentication;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

@Entity
@Table(name = "user_table")
public class User implements UserDetails {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * 
	 */

	@Id
	private Integer id;

	private String username;

	private String password;

	/**
	 * @return the id
	 */
	public Integer getId() {
		return id;
	}

	/**
	 * @param id the id to set
	 */
	public void setId(Integer id) {
		this.id = id;
	}

	/**
	 * @return the username
	 */
	public String getUsername() {
		return username;
	}

	/**
	 * @param username the username to set
	 */
	public void setUsername(String username) {
		this.username = username;
	}

	/**
	 * @return the password
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * @param password the password to set
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public Set<GrantedAuthority> getAuthorities() {
		Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
		authorities.add(new SimpleGrantedAuthority("USER"));
		return authorities;
	}

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
	}

}

Notice that the table name is given as “user_table” and not “user”. This is because in PostgreSQL , “user” is a restricted word and you cannot use it to create tables.

I have created only the three mandatory columns (id,username and password) and for the other fields required by UserDetails interface , I have returned default values .

STEP 4: Create the repository to access the User entity

package com.springboot.dbauthentication;

import org.springframework.data.jpa.repository.JpaRepository;



public interface UserRepository extends  JpaRepository<User, Integer>{

	
	public User findByUsername(String username);
}

I have used JpaRepository provided by Spring Data above.

Add a single method to fetch user by their name. This will be used in User Details service to fetch user by the name supplied in login screen.

STEP 5: Create User Details service

package com.springboot.dbauthentication;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {

	@Autowired
	private UserRepository repository;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

		User user = repository.findByUsername(username);
		if (user == null) {
			throw new UsernameNotFoundException(username);
		}

		return user;

	}

}

Implement UserDetailsService provided by Spring and create a User Details service. Override the method loadUserByUsername() and fetch the user from the repository inside the method.

Check if user is null and throw UsernameNotFoundException else if user is not found in database , Spring will complain that the interface contract has been violated.

STEP 6: Create security related configuration

Security related configuration are provided in WebSecurityConfigurationAdapter class . Create a class which extends this class. I have used all the default options provided by Spring Boot (like all the screens will be authenticated , default login form will be provided on launching the application etc).

So no configuration is added except for password encryption. Starting Spring 5.0 you can’t retrieve password as a plain text from database , so you need to store password in encrypted format and tell Spring how to decrypt it while fetching it from database.

I have used BCryptPasswordEncoder:

package com.springboot.dbauthentication;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

	@Bean(name = "pwdEncoder")
	public PasswordEncoder getPasswordEncoder() {
		DelegatingPasswordEncoder delPasswordEncoder = (DelegatingPasswordEncoder) PasswordEncoderFactories
				.createDelegatingPasswordEncoder();
		BCryptPasswordEncoder bcryptPasswordEncoder = new BCryptPasswordEncoder();
		delPasswordEncoder.setDefaultPasswordEncoderForMatches(bcryptPasswordEncoder);
		return delPasswordEncoder;
	}
	
	


}

STEP 7: Create users in the database:

I manually inserted records in user_table in postgreSQL database. For the password, I entered the value returned by encode method of BCryptPasswordEncoder API so that when Spring decrypts it the same encryption algorithm is used. You can generate them using a utility class with the below method:

	public static void main(String a[]) {
		BCryptPasswordEncoder bcryptPasswordEncoder = new BCryptPasswordEncoder();
		String pwd = bcryptPasswordEncoder.encode("password");
		System.out.println(pwd);
		
	}

STEP 8: Create an index.html file

By default Spring Boot will try to land the logged in user to index.html file or if there is any REST service created using the path “/” it will be invoked.

I just added Hello World message in the body of the index.html file

STEP 9: Verify

Launch the application on a browser. You will be shown a login form:

Once you enter your credentials , the contents in your index.html page will be displayed:

you can create new rest services and call them from index.html

They will use the jsessionid created by Spring Security (and stored in browser cookies) to make further requests which will not be authenticated again.

I created a simple RestController with a GET method which returns a message “I am a protected resource” and provided a link in index.html. On login the below page got displayed.

On clicking on Get Message , the REST service got called using the JSESSIONID stored in browser cookie and hence was not authenticated again:

If user tries to access the above link without login , the login form will be provided instead.

That’s it!

Authenticating using PostgreSQL database in Spring Boot is the same as authenticating through other relational databases like MySQL except that the keyword “User” is restricted in PostgreSQL , so you can’t use it to create the user table

Here is the code:

https://github.com/vijaysrj/spring-boot-postgresql-dbauthentication

To see how to preform user authorization see the below post:

https://fullstackdeveloper.guru/2021/02/15/how-to-do-user-authorization-in-spring-boot/


Posted

in

,

by

Comments

2 responses to “How to do user authentication in Spring Boot using PostgreSQL database?”

  1. Andrzej Avatar
    Andrzej

    Hi, how can I add to this code role like USER, ADMIN, …
    For example USER can enter only index, and ADMIN can enter index and other pages?

    1. Vijay SRJ Avatar
      Vijay SRJ

      Hi,
      you need to follow two extra steps to implement this:
      1) Create a new column named “role” in the entity class “User”
      2) Configure access rights in SecurityConfiguration class.

      Here is a detailed explanation:
      https://fullstackdeveloper.guru/2021/02/15/how-to-do-user-authorization-in-spring-boot/

Leave a Reply

Discover more from The Full Stack Developer

Subscribe now to keep reading and get access to the full archive.

Continue reading