Spring Boot Security 3.0 Flow

Shubham Wankhede
3 min readMar 6, 2023

--

we most of the times use spring boot security in our applications to to secure our application it can be either for authentication or authorization, but do we understand how spring internally handles the authentication and authorization, let’s understand it through this blog.

Before we get started have a look at below diagram and just read the different components so that you can little beforehand understanding of what we are going to see.

here we go, lot of components with no idea on what they are, worry not we understand them one by one.

1. Security Filter Chain

so whenever a user makes a call to any spring boot secured api it is first passes through security filter chain, what ? filters but why ? well as we all the filters are the classes in which is executed before execution of any endpoint method so if have to write any logic before processing our request we have to take the help of filters i.e here in this case Security Filters.

there are different filters we execute in chain like UsernamePasswordAuthenticationFilter and lastly untill it reaches to BasicAuthenticationFilter.

Security Filters extracts the username and password from request and then spring security creates a Authentication object out of it which then further can be used for validation and actual authentication purpose.

here is an example of Authentication Object.

UsernamePasswordAuthenticationToken authentication
= new UsernamePasswordAuthenticationToken(username, password);

2. Authentication Manager

AuthenticationManager is the component where our authenticate(-) method is there but AuthenticationManager is an interface and we have ProviderManager which is the implementation for our AuthenticationManager.

public interface AuthenticationManager {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
}

ProviderManager is the class which contains the actual implementation of authenticate(-) method, it also contains the logic to choose AuthenticationProvider for authentication based on the Authentication class.

so once we get the Authentication object from filters that object is passed to authenticate(-) method as method argument through AuthenticationManager -> ProviderManager

well it’s ok so far, but what is this AuthenticationProvider

3. Authentication Provider

AuthenticationProvider are the components which are responsible to process the request for certain type of authentication, it can be LDAP authentication, database user authentication or even our custom authentication provider which we can use by configuring it though security configuration.

In AuthenticationProvider we can get the user and perform the authentication,

public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class<?> authentication);
}

and as discussed previously the selection of AuthenticationProvider is based on the authentication class which we pass to authenticate method of ProviderManager.

Example of CustomAuthenticationProvider.

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider, Serializable {

@Autowired
private CustomUserDetailsService userDetailsService;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// fetch user from DB
try {
UserDetails userDetails = userDetailsService.loadUserByUsername(authentication.getName());
return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(),userDetails.getAuthorities());
}catch (UsernameNotFoundException e){
throw new BadCredentialsException("User authentication failed!!!!");
}

}

@Override
public boolean supports(Class<? extends Object> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}

security config for custom AuthenticationProvider

@EnableWebSecurity
@Configuration
public class SecurityConfig {

@Autowired
private CustomAuthenticationProvider authenticationProvider;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.csrf().disable()
.authorizeHttpRequests().anyRequest().authenticated()
.and().httpBasic()
.and().authenticationProvider(authenticationProvider)
.build();
}
}

4. UserDetailsService

We have UserDetailsService which then talks with Database to fetch the authenticating user details and they are used in AuthenticationProvider.

the UserDetailsService has loadByUsername(String username) method which we can use to fetch user from DB

we implement the same interface and return it through configs.

@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserInfoRepository userInfoRepository;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<UserInfo> userInfo = userInfoRepository.findByUsername(username);
return userInfo.map(UserDetailsModel::new).orElseThrow(()->new UsernameNotFoundException("Username Not Found"));
}
}

Security Config to return UserDetailsService object

@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}

In case if the authentication fails we Spring Security throus AuthenticationException.

5. Security Context

lastly once our authentication is successful spring security save the successfully authenticated user details in SecurityContext and wrap it using SecurityContextHolder.

if spring security finds SecurityContextHolder populated it assumes that the user is authenticated.

//code snippet from BasicAuthenticationFilter how authenticated user is saved in
//SecurityContext
Authentication authResult = this.authenticationManager.authenticate(authRequest);
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
context.setAuthentication(authResult);
this.securityContextHolderStrategy.setContext(context);

Hope you enjoyed the explanation.

--

--