Skip to the content.

Lesson 2: Step-by-Step Integration of Spring Security for Authentication


🎯 Lesson Objectives

By the end of this section, you will be able to:

✅ Identify security gaps in our existing authentication approach

✅ Gradually integrate Spring Security with SecurityFilterChain and JDBC-based authentication

Migrate the custom login flow (AuthenticationController) to Spring Security’s form login

✅ Use our existing USER_ADMIN table as the data source

✅ Understand the code updates and test them incrementally


1️⃣ Current Security Gaps

Before diving in, here are some potential gaps in our custom approach:

CSRF Protection: No CSRF tokens in forms—Spring Security can automatically handle this.

Session Fixation: Although you’re already using request.changeSessionId(), Spring Security offers a standard, configurable approach.

Concurrent Sessions: Not limited—Spring Security can manage maximum sessions per user.

Password Storage: Currently stored in plaintext—Spring Security uses password hashing (e.g., BCrypt) out-of-the-box.

Role-based Authorization: Not covered yet—Spring Security supports roles/authorities.


2️⃣ Step 1: Add Spring Security Dependencies

Maven pom.xml dependencies:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.8.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.8.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-crypto</artifactId>
    <version>5.8.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>5.7.10</version>
</dependency>

3️⃣ Step 2: Basic Spring Security Setup

Create a Spring Security configuration class:

package com.nicordesigns.site.config;

import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.core.userdetails.UserDetailsService;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/login", "/resources/**").permitAll()
                .anyRequest().authenticated()
            .and()
            .formLogin()
                .loginPage("/login")
                .defaultSuccessUrl("/registration/list")
                .failureUrl("/login?error")
                .permitAll()
            .and()
            .logout()
                .logoutSuccessUrl("/login?logout")
                .permitAll()
            .and()
            .csrf()  // ✅ CSRF protection enabled by default
            .and()
            .sessionManagement()
                .maximumSessions(1); // ✅ Limit concurrent sessions

        return http.build();
    }

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

    @Bean
    public UserDetailsService userDetailsService(DataSource dataSource) {
        JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource);
        users.setUsersByUsernameQuery(
            "SELECT USERNAME, PASSWORD, true as enabled FROM USER_ADMIN WHERE USERNAME = ?");
        users.setAuthoritiesByUsernameQuery(
            "SELECT USERNAME, 'ROLE_USER' FROM USER_ADMIN WHERE USERNAME = ?");
        return users;
    }
}

✅ Immediate Demonstration

Test:

✅ You’ll be redirected to /registration/list on success!


4️⃣ Step 3: Update our USER_ADMIN Table with BCrypt Passwords

Currently, passwords in USER_ADMIN are stored in plaintext. Let’s update them to BCrypt:

✅ Use an online tool (e.g., bcrypt-generator.com) or Java code to hash them:

public static void main(String[] args) {
    BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
    System.out.println(encoder.encode("Black")); // example output: $2a$10$...
}

SQL Update:

UPDATE charitydb.USER_ADMIN SET PASSWORD = '$2a$10$...' WHERE USERNAME = 'Nicolaas';
UPDATE charitydb.USER_ADMIN SET PASSWORD = '$2a$10$...' WHERE USERNAME = 'Danette';
UPDATE charitydb.USER_ADMIN SET PASSWORD = '$2a$10$...' WHERE USERNAME = 'Tom';

Demonstration: Try logging in again using the hashed passwords.


5️⃣ Step 4: Retire the Custom AuthenticationController Logic

Now that Spring Security’s form login and JDBC authentication are working:

Comment out or remove the AuthenticationController POST /login logic—it’s no longer needed! ✅ Spring Security automatically handles:

Your login.jsp form remains unchanged—it’s automatically handled by Spring Security.


6️⃣ Recap and Next Steps

Gaps filled:

Future tasks:


🚀 Final Demonstration

🔎 Test the new Spring Security flow:

1️⃣ Visit /login

2️⃣ Log in with an updated hashed password from USER_ADMIN

3️⃣ Access /registration/list—✅ protected!

4️⃣ Test /logout—✅ redirects back to /login

5️⃣ Confirm session fixation protection (changeSessionId() logs confirm new session)