Spring Boot 3: SecurityFilterChain Example

Spring Security 6 introduced a new way to configure security using SecurityFilterChain instead of the deprecated WebSecurityConfigurerAdapter. In this tutorial, we'll walk through setting up a Spring Boot 3 application with Spring Security 6 and demonstrate how to use SecurityFilterChain for security configuration.

Prerequisites

  • JDK 17 or later
  • Maven
  • Spring Boot (version 3.2+ recommended)
  • An IDE (IntelliJ IDEA, Eclipse, etc.)

Step 1: Set Up a Spring Boot Project Using Spring Initializr

Use Spring Initializr to generate a new Spring Boot project with the following configuration:

  • Project: Maven Project
  • Language: Java
  • Spring Boot: 3.2.x
  • Dependencies: Spring Web, Spring Security

Download the generated project, unzip it, and open it in your IDE.

Example Project Structure

The basic structure of a Spring Boot project with Maven looks like this:

my-spring-security-app/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/security/
│   │   │       └── SecurityApplication.java
│   │   │       └── config/
│   │   │           └── SecurityConfig.java
│   │   └── resources/
│   │       ├── application.properties
│   └── test/
│       └── java/
│           └── com/example/security/
│               └── SecurityApplicationTests.java
├── mvnw
├── mvnw.cmd
├── pom.xml
└── .mvn/
    └── wrapper/
        └── maven-wrapper.properties

Step 2: Configure pom.xml

Ensure your pom.xml file includes the necessary dependencies:

<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>
    <groupId>com.example</groupId>
    <artifactId>security</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>security</name>
    <description>Demo project for Spring Security</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>17</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-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Step 3: Create the Application Class

Create a Java class named SecurityApplication in the src/main/java/com/example/security directory.

package com.example.security;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SecurityApplication {

    public static void main(String[] args) {
        SpringApplication.run(SecurityApplication.class, args);
    }
}

Step 4: Configure Spring Security

Create a configuration class named SecurityConfig in the src/main/java/com/example/security/config directory.

package com.example.security.config;

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;

@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((requests) -> requests
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin((form) -> form
                .loginPage("/login")
                .permitAll()
            )
            .logout((logout) -> logout
                .permitAll()
            );
        return http.build();
    }
}

Explanation:

  • @Configuration: Marks this class as a configuration class.
  • @Bean: Indicates that a method produces a bean to be managed by the Spring container.
  • SecurityFilterChain: Configures the security filter chain.
  • http.authorizeHttpRequests: Configures URL authorization.
    • requestMatchers("/public/**").permitAll(): Allows public access to URLs starting with /public/.
    • anyRequest().authenticated(): Requires authentication for any other request.
  • http.formLogin: Configures form-based authentication.
    • loginPage("/login").permitAll(): Specifies a custom login page and allows public access to it.
  • http.logout: Configures logout functionality and allows public access to it.

Step 5: Create a Simple Controller

To verify the security configuration works as expected, let's create a simple controller.

Create a Java class named HomeController in the src/main/java/com/example/security directory:

package com.example.security;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HomeController {

    @GetMapping("/public/hello")
    @ResponseBody
    public String publicHello() {
        return "Hello, Public!";
    }

    @GetMapping("/private/hello")
    @ResponseBody
    public String privateHello() {
        return "Hello, Private!";
    }

    @GetMapping("/login")
    public String login() {
        return "login";
    }
}

Explanation:

  • @Controller: Marks this class as a Spring MVC controller.
  • @GetMapping("/public/hello"): Maps HTTP GET requests to the /public/hello endpoint.
    • publicHello method: Returns a "Hello, Public!" message.
  • @GetMapping("/private/hello"): Maps HTTP GET requests to the /private/hello endpoint.
    • privateHello method: Returns a "Hello, Private!" message.
  • @GetMapping("/login"): Maps HTTP GET requests to the /login endpoint.
    • login method: Returns the login page.

Step 6: Create a Login Page

Create a login.html file in the src/main/resources/templates directory.

<!DOCTYPE html>
<html>
<head>
    <title>Login</title>
</head>
<body>
    <h1>Login</h1>
    <form method="post" action="/login">
        <label for="username">Username:</label>
        <input type="text" id="username" name="username"><br>
        <label for="password">Password:</label>
        <input type="password" id="password" name="password"><br>
        <button type="submit">Login</button>
    </form>
</body>
</html>

Step 7: Run the Application

Using the Maven Wrapper

  1. Open a terminal: Navigate to the root directory of your Spring Boot project.

  2. Run the Application: Use the Maven wrapper to run the Spring Boot application:

For Unix/Linux/macOS:

./mvnw spring-boot:run

For Windows:

mvnw.cmd spring-boot:run

Using Maven Installed on Your Machine

If you have Maven installed on your machine, you can use the mvn command directly:

  1. Open a terminal: Navigate to the root directory of your Spring Boot project.

  2. Run the Application: Use the mvn command to run the Spring Boot application:

mvn spring-boot:run

Step 8: Verify the Application

  1. Public Endpoint:

    • URL: http://localhost:8080/public/hello
    • Method: GET
    • Response: Hello, Public!
  2. Private Endpoint:

    • URL: http://localhost:8080/private/hello
    • Method: GET
    • Response: You should be redirected to the login page.
  3. Login Page:

    • URL: http://localhost:8080/login
    • Method: GET
    • Response: The custom login page.

Conclusion

In this tutorial, you have learned how to set up Spring Security 6 using SecurityFilterChain instead of the deprecated WebSecurityConfigurerAdapter. We covered:

  • Setting up a Spring Boot project with Spring Security.
  • Configuring security

using SecurityFilterChain.

  • Creating a simple controller with public and private endpoints.
  • Creating a custom login page.
  • Running and verifying the application.

By following these steps, you can secure your Spring Boot applications using the latest Spring Security features.

Comments