Spring Security - How It Works
Spring Security is a powerful and highly customizable authentication and access-control framework
for Java applications, especially those built with Spring. It helps developers secure their apps by
handling:
- Authentication (who are you?)
- Authorization (what are you allowed to do?)
1. Authentication Flow
- A user tries to log in (e.g., via a login form).
- Spring Security intercepts the login request using a UsernamePasswordAuthenticationFilter.
- It passes the credentials to an AuthenticationManager.
- This manager uses an AuthenticationProvider (like DaoAuthenticationProvider) to verify the
credentials.
- If successful, it returns an Authentication object and stores it in the SecurityContext.
2. Authorization Flow
- This determines if a user has permission to access a specific resource.
- You can configure URL-based access or use annotations like @PreAuthorize.
3. SecurityContext and Filters
- Every request is checked through the Security Filter Chain.
- Authenticated user info is stored in the SecurityContextHolder (usually stored in session).
4. Customizations
- Custom login page, UserDetailsService, filters, JWT, OAuth2, etc.
Example Java Config:
http
.authorizeHttpRequests()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated();
---
Real-World Example: Securing a REST API
1. Dependencies (Maven)
- spring-boot-starter-security
- spring-boot-starter-web
2. UserDetailsService Implementation:
@Service
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) {
if (username.equals("admin")) {
return User.builder()
.username("admin")
.password(new BCryptPasswordEncoder().encode("admin123"))
.roles("ADMIN")
.build();
} else if (username.equals("user")) {
return User.builder()
.username("user")
.password(new BCryptPasswordEncoder().encode("user123"))
.roles("USER")
.build();
throw new UsernameNotFoundException("User not found");
3. Security Configuration:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN")
.requestMatchers("/user/**").hasRole("USER")
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
4. Controller Endpoints:
@RestController
public class TestController {
@GetMapping("/public/hello")
public String publicHello() {
return "Hello from public!";
@GetMapping("/user/hello")
public String userHello() {
return "Hello user!";
@GetMapping("/admin/hello")
public String adminHello() {
return "Hello admin!";
Testing:
- /public/hello ? No login needed
- /user/hello ? Login as user/user123
- /admin/hello ? Login as admin/admin123