Spring Security Guide: Authentication, Authorization, and Customizing Filter Chains
This guide introduces Spring Security fundamentals, explaining authentication and authorization concepts, the core interfaces such as AuthenticationManager and AccessDecisionManager, how to configure them with Spring Boot, customize filter chains, apply method‑level security, and handle thread‑bound security contexts for asynchronous processing.
This guide provides an introductory overview of Spring Security, focusing on its design, core components, and practical usage for securing Java web applications.
Authentication and Access Control
Application security is divided into two independent concerns: authentication (who you are) and authorization (what you can do). Spring Security separates these concerns via extensible strategies and extension points.
Authentication
The primary strategy interface is AuthenticationManager, which defines a single method:
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
}The authenticate() method can return a successful Authentication object, throw an AuthenticationException, or return null when it cannot decide.
The most common implementation is ProviderManager, which delegates to a chain of AuthenticationProvider instances. Each provider implements:
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class<?> authentication);
}If none of the providers support the supplied authentication type, the chain falls back to an optional parent manager.
Customizing Authentication Managers
Spring Security offers helpers such as AuthenticationManagerBuilder to configure in‑memory, JDBC, or LDAP user details. Example configuration:
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Autowired
public void initialize(AuthenticationManagerBuilder builder, DataSource dataSource) {
builder.jdbcAuthentication()
.dataSource(dataSource)
.withUser("dave")
.password("secret")
.roles("USER");
}
}When the builder is used as a method‑parameter bean, it creates a global (parent) AuthenticationManager. Declaring it as a regular @Bean builds a local manager that is a child of the global one.
Authorization (Access Control)
After successful authentication, Spring Security uses AccessDecisionManager to decide whether access is granted. The default implementation is AffirmativeBased, which grants access if any AccessDecisionVoter votes to allow.
Voters evaluate Authentication and ConfigAttribute metadata, often expressed as role strings (e.g., ROLE_ADMIN) or SpEL expressions such as isFullyAuthenticated() && hasRole('FOO').
Web Security Filter Chain
Spring Security is installed as a single FilterChainProxy bean that delegates to an ordered list of internal filters. The chain order is crucial and can be controlled via @Order, Ordered, or FilterRegistrationBean. The default chain for a Spring Boot application contains about eleven filters handling authentication, exception handling, session management, header writing, etc.
Multiple filter chains can be defined, each with its own request matcher (e.g., /api/** vs. static resources). The first matching chain wins.
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
public class ApplicationConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/foo/**")
.authorizeRequests()
.antMatchers("/foo/bar").hasRole("BAR")
.antMatchers("/foo/spam").hasRole("SPAM")
.anyRequest().isAuthenticated();
}
}Method Security
Beyond web filters, Spring Security can protect Java method invocations. Enable it with @EnableGlobalMethodSecurity(securedEnabled = true) and annotate methods using @Secured, @PreAuthorize, or @PostAuthorize:
@Service
public class MyService {
@Secured("ROLE_USER")
public String secure() {
return "Hello Security";
}
}Thread‑Bound Security Context
The SecurityContext (holding the current Authentication) is stored in a ThreadLocal via SecurityContextHolder. Access it directly when needed:
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
assert authentication.isAuthenticated();When executing code asynchronously (e.g., with @Async), propagate the context using helpers such as DelegatingSecurityContextExecutorService:
@Configuration
public class ApplicationConfiguration extends AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
return new DelegatingSecurityContextExecutorService(Executors.newFixedThreadPool(5));
}
}These utilities ensure that background tasks retain the security information of the originating request.
Author: before31 – https://my.oschina.net/xuezi/blog/3126351
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
