Core Components of Spring Security

Spring Security is a comprehensive framework for handling authentication and authorization in Spring-based applications. It offers out-of-the-box support for securing your application with industry-standard practices and mechanisms. Whether you're developing a simple web application or a complex microservices architecture, understanding the core components of Spring Security is crucial for implementing robust security measures. This blog post will guide you through Spring Security's core components with examples.

Core Components of Spring Security

Spring Security's architecture revolves around several key components that work together to secure your applications. Here, we'll explore these components and provide examples using current best practices.

1. Authentication

Authentication is the process of verifying a user's or system's identity. It answers the question, "Who are you?" Spring Security supports various authentication mechanisms, such as form-based login, OAuth2, and more, without relying on deprecated classes.

Modern Example:

@Configuration
    @EnableWebSecurity
    public class SecurityConfig {
    
        @Bean
        public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
            http
                .authorizeHttpRequests((authorize) -> authorize
                    .anyRequest().authenticated()
                )
                .httpBasic(Customizer.withDefaults())
                .formLogin(Customizer.withDefaults());
    
            return http.build();
        }
    
        @Bean
        public UserDetailsService userDetailsService() {
            UserDetails userDetails = User.withDefaultPasswordEncoder()
                .username("user")
                .password("password")
                .roles("USER")
                .build();
    
            return new InMemoryUserDetailsManager(userDetails);
        }
    
    }

2. Authorization

After authentication, authorization determines whether the authenticated user has permission to perform a given action or access a resource. It answers, "Are you allowed to do this?"

Modern Example:

@Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeRequests(authorize -> authorize
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated())
            .formLogin().and()
            .httpBasic();
        return http.build();
    }

3. Principal

A principal refers to the currently authenticated user's details, accessible throughout the application for user-specific operations.

Usage Example:

4. Granted Authority

Granted authorities define permissions for authenticated users, specifying what actions they can perform or resources they can access.

Example:

@Bean
                public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
                    http
                        .authorizeRequests(authorize -> authorize
                            .antMatchers("/api/private/**").hasAuthority("ROLE_USER")
                            .anyRequest().permitAll())
                        .httpBasic();
                    return http.build();
                }

5. Security Context and SecurityContextHolder

At the heart of Spring Security is the SecurityContext, which holds the details of the currently authenticated user, also known as the principal. This context is accessible throughout the application via the SecurityContextHolder, allowing you to perform operations based on the user's authentication status and authorities.

Example:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                if (authentication != null && authentication.isAuthenticated()) {
                    // Perform operations based on the authenticated user
                }

6. UserDetails

The UserDetails interface is a central piece in Spring Security, representing the user information that Spring Security uses for authentication and authorization processes. It provides core user information to the framework, such as:

Implementing UserDetails allows you to integrate your application's user entity with Spring Security seamlessly.

7. UserDetailsService

UserDetailsService is an interface used by Spring Security to retrieve user-related data. It has a single method, loadUserByUsername(String username), which locates the user based on the username. The returned UserDetails object then becomes available to Spring Security for further authentication and authorization processes.

Implementing your own UserDetailsService involves creating a service that interacts with your user database (or another user storage mechanism) to fetch user details and convert them into a UserDetails object. This custom service becomes a bridge between your user data and Spring Security's requirements.

8. AuthenticationManager

At the core of the Spring Security authentication process is the AuthenticationManager interface. It defines a single method, authenticate(Authentication authentication), which attempts to authenticate the passed Authentication object. The AuthenticationManager is responsible for orchestrating the authentication process by delegating the request to one or more AuthenticationProvider instances.

Each AuthenticationProvider can handle a specific type of authentication (e.g., username and password, token-based authentication, etc.). The AuthenticationManager routes the authentication request to the provider capable of handling it, based on the type of Authentication object it receives.

The successful authentication process results in a fully populated Authentication object, including the principal and granted authorities, which is then stored in the SecurityContext for subsequent authorization checks.

Configuring AuthenticationManager

In the new configuration approach without WebSecurityConfigurerAdapter, you can expose an AuthenticationManager bean directly within your configuration class. Here's an example of how it can be done:

@EnableWebSecurity
                public class SecurityConfig {
                
                    @Bean
                    @Override
                    protected AuthenticationManager authenticationManager() throws Exception {
                        return super.authenticationManager();
                    }
                
                    // SecurityFilterChain and other beans configuration
                }