Filter chain

Customizing the filter chain

Spring Security uses the concept of the filter chain. This is a sophisticated interceptor that is placed in front of the controllers.

The filter chain is configured by creating a bean of type SecurityFilterChain. Spring Security provides a fluid API (see builder pattern) that centralizes the application rules.

securityfilterchain

Access restricted to authenticated users

Note
For the demo, we are creating a Spring Boot application with some Spring MVC views, backed with the Thymeleaf templating tool. We will also need some extra support for Spring Security.
1implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity6")
 1<!DOCTYPE html>
 2<html lang="en"
 3      xmlns:th="http://www.thymeleaf.org">
 4<head>
 5    <meta charset="UTF-8">
 6    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7    <title>Home</title>
 8</head>
 9<body>
10    <h1>Welcome to the Public Home Page</h1>
11    <ul>
12        <li><a th:href="@{/secure}">Go to Secure Page</a></li>
13        <li><a th:href="@{/login}">Login</a></li>
14    </ul>
15</body>
16</html>
 1<!DOCTYPE html>
 2<html lang="en"
 3      xmlns:th="http://www.thymeleaf.org"
 4      xmlns:sec="http://www.w3.org/1999/xhtml">
 5<head>
 6    <meta charset="UTF-8">
 7    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 8    <title>Secure</title>
 9</head>
10<body>
11    <h1>Welcome to the Secure Page</h1>
12    <p>You are logged in as <span sec:authentication="name"></span></p>
13    <p>You are granted these authorities: <span sec:authentication="principal.authorities"></span></p>
14    <ul>
15        <li><a th:href="@{/}">Back to Home</a></li>
16        <li><a th:href="@{/logout}">Logout</a></li>
17    </ul>
18</body>
19</html>
 1package fr.emse.tbpwme3.demo.spring.security;
 2
 3import org.springframework.context.annotation.Bean;
 4import org.springframework.context.annotation.Configuration;
 5import org.springframework.security.config.Customizer;
 6import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 7import org.springframework.security.web.SecurityFilterChain;
 8
 9@Configuration
10public class SecurityConfig {
11
12    @Bean
13    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
14        http
15                .authorizeHttpRequests(c -> c.requestMatchers("/secure")
16                        .authenticated())
17                .authorizeHttpRequests(c -> c.anyRequest()
18                        .permitAll())
19                .formLogin(Customizer.withDefaults());
20        return http.build();
21    }
22
23}

The code above describes the application’s filter chain.

  • Access to the /secure path requires authentication.

  • Access to all other paths is unrestricted.

  • Authentication is provided via the login form.

 1package fr.emse.tbpwme3.demo.spring.security;
 2
 3import org.springframework.stereotype.Controller;
 4import org.springframework.web.bind.annotation.GetMapping;
 5
 6@Controller
 7public class HomeController {
 8
 9    @GetMapping("/")
10    public String home() {
11        return "home";
12    }
13
14    @GetMapping("/secure")
15    public String secure() {
16        return "secure";
17    }
18
19}

Access restricted to users with the required authorities

When the application starts, we create two users, user with the USER role and admin with the USER and ADMIN roles.

 1@Bean
 2DataSource dataSource() {
 3    return new EmbeddedDatabaseBuilder()
 4            .setType(H2)
 5            .addScript(JdbcDaoImpl.DEFAULT_USER_SCHEMA_DDL_LOCATION)
 6            .build();
 7}
 8
 9@Bean
10UserDetailsManager users(DataSource dataSource) {
11    UserDetails user = User.builder()
12            .username("user")
13            .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
14            .roles("USER")
15            .build();
16    UserDetails admin = User.builder()
17            .username("admin")
18            .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
19            .roles("USER", "ADMIN")
20            .build();
21    JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource);
22    users.createUser(user);
23    users.createUser(admin);
24    return users;
25}
Note
Both user and admin have password for password.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
            .authorizeHttpRequests(c -> c.requestMatchers("/admin")
                    .hasAuthority("ROLE_ADMIN"))
            .authorizeHttpRequests(c -> c.requestMatchers("/secure")
                    .authenticated())
            .authorizeHttpRequests(c -> c.anyRequest()
                    .permitAll())
            .formLogin(Customizer.withDefaults());
    return http.build();
}

We update the filter chain so that the /admin path requires the ADMIN role.

Note
hasAuthority("ROLE_ADMIN") is the same as hasRole("ADMIN").