Spring Security in Java
Introduction
Security is a paramount concern in modern software development. Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications.
Spring Security deals primarily with two major concepts:
- Authentication: Proving who you are (e.g., username/password, JWT, OAuth2).
- Authorization (Access Control): Deciding what you are allowed to do (e.g., Admin vs. User roles).
Deep Dive: Architecture
Spring Security operates by chaining a series of Servlet Filters in front of your application's DispatcherServlet.
- DelegatingFilterProxy: A standard Servlet filter that delegates work to a Spring-managed bean.
- FilterChainProxy: The Spring bean that manages the internal security filters.
- SecurityFilterChain: A chain of filters (like
UsernamePasswordAuthenticationFilter,BasicAuthenticationFilter, etc.) that process the request sequentially to enforce security.
The SecurityContextHolder is a thread-local storage that holds the details of the currently authenticated user (the Authentication object), ensuring that security details are easily accessible anywhere in the request thread.
Code Examples
1. Basic Security Configuration
Modern Spring Security configuration relies on defining a SecurityFilterChain bean rather than extending WebSecurityConfigurerAdapter (which is deprecated).
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // Often disabled for stateless REST APIs
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.httpBasic(basic -> {}); // Enables Basic Authentication
return http.build();
}
}
2. Method-Level Security
Sometimes, URL-based security isn't granular enough. Method-level security allows you to secure individual service methods.
Enable it first:
@Configuration
@EnableMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
}
Use it in your services:
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class DocumentService {
@PreAuthorize("hasRole('ADMIN') or #document.owner == authentication.name")
public void deleteDocument(Document document) {
// Logic to delete document
}
}
3. UserDetailsService
To load user-specific data during authentication, implement the UserDetailsService.
import org.springframework.security.core.userdetails.*;
import org.springframework.stereotype.Service;
@Service
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User not found"));
return org.springframework.security.core.userdetails.User
.withUsername(user.getUsername())
.password(user.getPassword())
.roles(user.getRole())
.build();
}
}
Advanced Usage: Stateless JWT Authentication
For modern REST APIs and Microservices, session-based authentication is often replaced by stateless JWT (JSON Web Tokens).
Implementing JWT in Spring Security involves:
- Creating a custom filter that intercepts requests, extracts the JWT from the
Authorizationheader, and validates it. - If valid, manually creating an
Authenticationtoken and setting it in theSecurityContextHolder. - Configuring
SessionCreationPolicy.STATELESSin theHttpSecurityconfiguration.
Summary
- Spring Security provides comprehensive authentication and authorization using a robust Filter Chain architecture.
- Modern configuration is achieved via
SecurityFilterChainbeans. - It supports URL-based rules, method-level annotations (
@PreAuthorize), and seamlessly integrates with JWT, OAuth2, and LDAP.