How does Spring Boot integrate with Spring Security?
Spring Boot dramatically simplifies the integration and configuration of Spring Security, making it easier to add robust authentication and authorization to applications. It achieves this through auto-configuration, sensible defaults, and dedicated starter dependencies, significantly reducing the amount of boilerplate code required.
1. Starter Dependencies
The primary mechanism for integrating Spring Security with Spring Boot is the spring-boot-starter-security dependency. Adding this single dependency to your project brings in all necessary Spring Security modules and triggers Spring Boot's auto-configuration.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
implementation 'org.springframework.boot:spring-boot-starter-security'
2. Auto-Configuration and Default Behavior
Once the security starter is present, Spring Boot automatically configures a default security setup. This includes:
- Default Login Page: A basic form-based login page is automatically generated and secured for all requests.
- In-memory User: A default user (
user) with a randomly generated password is created at startup. This password is printed to the console/logs. - Basic Authentication: For non-browser clients (e.g., REST APIs), HTTP Basic authentication is enabled by default.
- CSRF Protection: Cross-Site Request Forgery protection is enabled by default for state-changing HTTP methods (POST, PUT, DELETE).
- Session Management: Default session management is configured.
This out-of-the-box configuration allows developers to quickly get a secured application running without writing any security-specific code, providing immediate protection.
3. Customizing Security Configuration
While the defaults are useful for quick starts, real-world applications require customization. Spring Boot allows this by letting developers define their own SecurityFilterChain bean or extend WebSecurityConfigurerAdapter (though SecurityFilterChain is the modern and recommended approach since Spring Security 5.7+). By defining custom security configurations, developers can:
- Define custom authentication providers (e.g., JDBC, LDAP, OAuth2).
- Configure specific authorization rules for different URLs (
antMatchers,requestMatchers). - Disable or configure CSRF protection.
- Integrate with OAuth2, JWT, or other token-based authentication mechanisms.
- Customize the login/logout process and pages.
Here's an example of a basic custom SecurityFilterChain configuration:
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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/", "/home", "/public").permitAll()
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
.logout(logout -> logout.permitAll());
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
4. Externalizing Security Properties
Spring Boot also allows basic security properties to be configured via application.properties or application.yml. For instance, you can define a default in-memory user directly in the properties file without writing Java code:
spring.security.user.name=admin
spring.security.user.password=mysecretpassword
spring.security.user.roles=USER,ADMIN
5. Method-Level Security
For fine-grained authorization, Spring Boot supports Spring Security's method-level security. By enabling @EnableMethodSecurity (or @EnableGlobalMethodSecurity for older versions) and using annotations like @PreAuthorize, @PostAuthorize, @Secured, or @RolesAllowed, you can secure individual methods based on user roles or expressions.
@RestController
@RequestMapping("/api")
@EnableMethodSecurity // Or @EnableGlobalMethodSecurity
public class MyController {
@GetMapping("/admin-data")
@PreAuthorize("hasRole('ADMIN')")
public String getAdminData() {
return "This is sensitive admin data.";
}
@GetMapping("/user-data")
@PreAuthorize("hasAnyRole('USER', 'ADMIN')")
public String getUserData() {
return "This is user data.";
}
}