Spring Security: Postgres DB Integration: Part 1

Sabyasachi Mohanty
5 min readMay 6, 2021

If you are a starter to Spring Security I would suggest you start from Spring Security: The Begining.

This article is divided into 2 parts. The first part will tell you about the Spring security setup, while the next part will focus on hands-on.

After reading these articles, you will understand —

  1. … how user data is processed and stored in the Database.
  2. … how do we encrypt the passwords before storing them.
  3. … various classes and methods we will be using and why we use them?
Spring Security

Let’s go —

Step — 1: Add the following dependencies to the pom file.

I would be integrating my Spring Boot app with the Postgres database.

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

Here we have added —

  1. Spring boot starter data rest for rest calls.
  2. Spring boot starter security for securing applications.
  3. Spring boot starter data JPA for DB interactions.
  4. Postgresql driver class

Step — 2: Connecting to a Database

I will be using Postgresql. Hence the following configurations must be included in the application.properties file.

spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.database=POSTGRESQL
spring.datasource.platform=postgres
spring.jpa.show-sql=true
spring.datasource.url=jdbc:postgresql://localhost:5432/<database>
spring.datasource.username=<user_name>
spring.datasource.password=<password>

Step — 3: Setting up SecurityConfig Class

We are now creating a class SecurityConfig that will help us with the authentication. This class must extend WebSecurityConfigurerAdapter

@Component
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

}

@EnableWebSecurity tag tells Spring security that we will be passing our own configurations for authentication and authorization. It need not have to use its default configs.

WebSecurityConfigurerAdapter” — this parent class comes with methods that help us with authentication and authorization.

Step — 4: Password Encoder

Let’s add a password encoder inside the “SecurityConfig” class.

@Bean
protected PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

BCryptPasswordEncoder — More on this here.

What is the use of this method? — say, as a user you are trying to login into the application. For this, you enter your username and password and click on login, which will pass your credentials to the application’s security config for authentication and authorization.

But Spring focuses on password encoding and also expects its developers to follow the same. This is where the method comes to the picture. PasswordEncoder thus helps encode the password while it is being passed on to the spring security configs.

Here’s the catch, just by doing this, we aren't pushing encoded password into our database. For this to happen, we need to encode it explicitly. I will show you how it's done in a while. (It’s code and its working is covered in the part 2 of the article)

Step — 5: Adding Authentication Rules

@Autowired
private CustomUserDetailsService customUserDetailService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailService);
}

Here, we are overriding configure method with our own set of configs. Configure is using AuthenticationManagerBuilder as a parameter and we will be using this reference to set our rules for authentication.

Why do we need this method? — Once we get the user information, now what? We need to retrieve data from a store and check if the creds passed to us and the database, are matching. No matter the type of authentication we do, the only change is how you retrieve the user and from where you retrieve it. Other than this the various checks that we make, are all the same. Hence Spring Security thought of saving our time by creating its own entity for this purpose, which is called as UserDetailsService.

Hence, to this method, we are passing a reference customUserDetailService of type CustomUserDetailsService class.

Step — 6: Defining our “CustomUserDetailService” class.

For this, we will be creating a new class, something like this —

@Service
public class CustomUserDetailsService implements UserDetailsService {

@Autowired
private AuthDao authDao;

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

Authentication auth = authDao.findByEmail(userName);

/*******************************************************
* YOU CAN ADD YOUR OWN LOGIC HERE LIKE -
* 1. check if the account is active
* 2. check if the account is blocked
* 3. all the active roles assigned to this user
* 4. and many more...
*******************************************************/

return new User(auth.getEmail(), auth.getPassword(), new ArrayList<>());
}
}

CustomUserDetailsService is implementing UserDetailsService and we have to override a method loadUserByUsername that takes in a username of type String and returns an Entity — UserDetails.

Here, we are first retrieving the data from our database based on the username passed to us. After which we can add our own logic to determine if the user is valid. This can also be done using the same query used for retrieving user info from the DB. Hence, I have kept this as optional, anything that works for you is fine. In the end, we are returning an object of type User by populating details like username, password and the roles of that particular user.

Let’s understand UserDetails and User classes —

UserDetails — Interface. Provides core user information. They simply store user information which is later encapsulated into Authentication objects. This allows non-security related user information (such as email addresses, telephone numbers etc) to be stored in a convenient location.

User — class implementing UserDetails Interface. Models core user information retrieved by a UserDetailsService. It implements the CredentialsContainer interface, in order to allow the password to be erased after authentication.

Step — 7: Adding Authorization to the “SpringConfig” class.

@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/admin").hasRole("ADMIN")
.antMatchers("/users").hasAnyRole("USER", "ADMIN")
.antMatchers("/register", "/").permitAll()
.and().formLogin();
}

Here, we are overriding another configure method that uses HttpSecurity as a parameter. In this method, we are telling spring security one user must have sufficient roles to access certain endpoints.

I have already discussed this in detail here — https://sabya-writes.medium.com/spring-security-implementation-basics-157f8d7023f7

So far, we have seen —

  1. how to set up a data source.
  2. how to create our own classes to define our authentication rules.
  3. how to set up a password encoder.
  4. how to authorize.

In Part — 2 of the article —

We will see, how user details are persisted in our database and how the data looks after saving in the DB. I will try to explain how these components are connected.

Part 2 of the article: https://sabya-writes.medium.com/spring-security-postgres-db-integration-part-2-b4e408150455

For the code, you can fork to https://github.com/Lincoln13/spring-security-jdbc

--

--