Security Configuration (Spring Security DSL)

About

Spring Security DSL (Domain-Specific Language) is the modern way to configure security in Spring Boot without extending WebSecurityConfigurerAdapter. It was introduced in Spring Security 5 and became the default approach in Spring Boot 3.

This approach uses lambda-based security configuration to define authentication, authorization, and other security settings more concisely.

Spring Security DSL -

  • Eliminates WebSecurityConfigurerAdapter – No need to override configure().

  • More readable and flexible – Uses fluent, declarative API.

  • Better compatibility with functional and reactive programming.

  • Aligns with Spring Boot's convention-over-configuration philosophy.

Components of Spring Security Configuration

Spring Security DSL is built on several core components:

Component

Description

SecurityFilterChain

Defines HTTP security rules.

HttpSecurity

Configures security settings.

AuthenticationManager

Handles authentication logic.

UserDetailsService

Loads user details from DB.

PasswordEncoder

Encrypts and verifies passwords.

AuthenticationProvider

Custom authentication logic.

SecurityContext

Holds authenticated user details.

Security Configuration

Before (Spring Boot 2 - Extending WebSecurityConfigurerAdapter)

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/admin").hasRole("ADMIN")
            .antMatchers("/user").hasRole("USER")
            .anyRequest().authenticated()
            .and()
            .formLogin();
    }
}
  • Uses the old WebSecurityConfigurerAdapter class (deprecated in Spring Boot 3).

After (Spring Boot 3 - Using Security DSL)

@Configuration
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/admin").hasAuthority("ROLE_ADMIN")
                .requestMatchers("/user").hasAuthority("ROLE_USER")
                .anyRequest().authenticated()
            )
            .formLogin(withDefaults());
        return http.build();
    }
}
  • Uses SecurityFilterChain with HttpSecurity DSL instead of extending WebSecurityConfigurerAdapter.

  • requestMatchers() replaces antMatchers().

Examples

1. Configuring Authentication (In-Memory Users)

@Bean
public UserDetailsService userDetailsService() {
    UserDetails admin = User.withUsername("admin")
        .password(passwordEncoder().encode("admin123"))
        .roles("ADMIN") // Automatically adds "ROLE_ADMIN"
        .build();

    UserDetails user = User.withUsername("user")
        .password(passwordEncoder().encode("user123"))
        .roles("USER")
        .build();

    return new InMemoryUserDetailsManager(admin, user);
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}
  • Defines users in-memory (for testing).

  • Uses BCryptPasswordEncoder for secure password hashing.

2. Configuring Authentication (Database UserDetailsService)

@Service
public class CustomUserDetailsService implements UserDetailsService {
    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("User not found"));

        List<GrantedAuthority> authorities = user.getRoles().stream()
                .map(role -> new SimpleGrantedAuthority(role.getName()))
                .collect(Collectors.toList());

        return new org.springframework.security.core.userdetails.User(
                user.getUsername(), user.getPassword(), authorities);
    }
}
  • Retrieves users and roles from database dynamically.

3. Defining Custom AuthenticationManager

@Bean
public AuthenticationManager authenticationManager(UserDetailsService userDetailsService, 
                                                   PasswordEncoder passwordEncoder) throws Exception {
    return new ProviderManager(List.of(new DaoAuthenticationProvider() {{
        setUserDetailsService(userDetailsService);
        setPasswordEncoder(passwordEncoder);
    }}));
}
  • Custom AuthenticationManager with UserDetailsService and PasswordEncoder.

4. Role-Based Authorization

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/admin").hasRole("ADMIN")
            .requestMatchers("/user").hasRole("USER")
            .anyRequest().authenticated()
        )
        .formLogin(Customizer.withDefaults());
    return http.build();
}
  • Restricts /admin to ROLE_ADMIN and /user to ROLE_USER.

5. Permission-Based Authorization

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/edit").hasAuthority("EDIT_PRIVILEGE")
            .requestMatchers("/delete").hasAuthority("DELETE_PRIVILEGE")
            .anyRequest().authenticated()
        )
        .formLogin(Customizer.withDefaults());
    return http.build();
}
  • Uses fine-grained permission-based access control.

6. Enabling JWT-Based Authentication

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf(csrf -> csrf.disable()) // Disable CSRF for JWT
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/admin").hasRole("ADMIN")
            .anyRequest().authenticated()
        )
        .addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class);
    return http.build();
}
  • Integrates JWT authentication into Spring Security filter chain.

Last updated

Was this helpful?