Spring Security
Getting Started
Add Spring Security Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Spring Security will automatically add basic authentication to all endpoints once this dependency is added.
Understanding Key Components
- Authentication: Verifies the user's identity.
- Authorization: Determines if an authenticated user has permission to perform specific actions.
- Principal: Represents the current authenticated user in the application.
- Roles & Authorities: Roles are high-level groupings of authorities (permissions) that define access levels.
Configuring Authentication
You can use multiple methods for authentication in Spring Security:
In-Memory Authentication (for Prototyping or Testing)
Configure in-memory authentication with specific users and roles.
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER")
.and()
.withUser("admin").password("{noop}admin").roles("ADMIN");
}
}
{noop}
is a password encoder that tells Spring Security to expect plain text. Use other password encoders like BCryptPasswordEncoder
in production.
Database Authentication
For production, authenticate users from a database.
- Define a UserDetailsService implementation that fetches user details from the database.
- Use a Password Encoder for storing hashed passwords.
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
JWT Authentication
To use JWT tokens for authentication:
- Create a login endpoint that generates a JWT upon successful authentication.
- Configure a
JWTAuthenticationFilter
to validate tokens on each request.
Authorization: Configuring Access Control
Authorization configurations control access to resources based on roles or permissions.
Role-Based Access Control
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin();
}
Method-Level Authorization
Use annotations to restrict access at the method level:
@PreAuthorize
– To check access before method execution.@Secured
– Specify roles required to access the method.
@PreAuthorize("hasRole('ADMIN')")
public void someAdminMethod() {
// Method logic
}
Enable method-level security with:
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends WebSecurityConfigurerAdapter {
}
Handling CORS and CSRF
CORS (Cross-Origin Resource Sharing)
Enable CORS for REST APIs that might be accessed from a different domain:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://allowed-origin.com"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
CSRF (Cross-Site Request Forgery)
By default, CSRF is enabled. You can disable it for stateless APIs (like JWT):
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
Only disable CSRF if you know it is not needed, such as with stateless REST APIs.
Session Management
Spring Security manages sessions by default. You can configure session policies to meet your security requirements:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS); // For JWT or token-based authentication
}
Options:
SessionCreationPolicy.ALWAYS
: Always create a session.SessionCreationPolicy.IF_REQUIRED
: Create a session only if required.SessionCreationPolicy.NEVER
: Never create a session but use one if it exists.SessionCreationPolicy.STATELESS
: Do not store sessions.
Custom Authentication & Authorization Logic
To add custom authentication:
- Create an
AuthenticationProvider
to customize user validation. - Implement custom filters for additional request checks (e.g.,
OncePerRequestFilter
).
Configuring OAuth2 and Social Login
For OAuth2 authentication:
- Add the
spring-boot-starter-oauth2-client
dependency. - Configure
application.yml
orapplication.properties
with your provider settings.
spring:
security:
oauth2:
client:
registration:
google:
client-id: your-client-id
client-secret: your-client-secret
scope: profile, email
Spring Boot simplifies this setup with OAuth providers like Google, GitHub, etc.
Testing Security Configurations
- Unit Testing: Use
@WithMockUser
to simulate users with specific roles for testing. - Integration Testing: Test endpoints with and without authentication to verify security configurations.
@Test
@WithMockUser(username = "user", roles = {"USER"})
public void whenUserAccessUserPage_thenSuccess() throws Exception {
mvc.perform(get("/user/page")).andExpect(status().isOk());
}
Best Practices
- Use Strong Password Encoders: Always use a secure password encoder like
BCryptPasswordEncoder
. - Limit Session and Token Lifespan: Configure session timeouts or token expiration to reduce attack windows.
- Enable HTTPS: Secure communications by configuring HTTPS in production.
- Restrict Sensitive Endpoints: Limit access to admin or critical endpoints by roles or permissions.
- Use Custom Error Handling: Customize error messages for failed authentications to avoid information disclosure.