Spring Security Annotations
Spring Security provides a set of annotations to handle authentication and authorization at the method level. These annotations simplify the process of securing methods within your Spring applications. This guide covers the key Spring Security annotations and how to use them effectively.
Key Spring Security Annotations
- @EnableWebSecurity: Enables Spring Security’s web security support and provides the Spring MVC integration.
- @PreAuthorize: Specifies a method should be accessible only if the specified expression evaluates to true before the method is invoked.
- @PostAuthorize: Specifies a method should be accessible only if the specified expression evaluates to true after the method is invoked.
- @Secured: Specifies one or more roles that are allowed to invoke a method.
- @RolesAllowed: Similar to @Secured but uses standard JSR-250 annotations.
- @EnableGlobalMethodSecurity: Enables method-level security.
Setting Up Dependencies
Include the Spring Security dependency in your pom.xml
file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Enabling Method-Level Security
Enable method-level security by adding the @EnableGlobalMethodSecurity
annotation in your configuration class:
Example: SecurityConfiguration.java
// SecurityConfiguration.java
package com.example.myapp.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfiguration {
// Security configuration code
}
Using @PreAuthorize
The @PreAuthorize
annotation is used to specify an authorization expression that will be evaluated before a method is invoked:
Example: MyService.java
// MyService.java
package com.example.myapp.service;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@PreAuthorize("hasRole('ADMIN')")
public void adminMethod() {
// Admin only logic
}
@PreAuthorize("hasRole('USER')")
public void userMethod() {
// User only logic
}
}
Using @PostAuthorize
The @PostAuthorize
annotation is used to specify an authorization expression that will be evaluated after a method is invoked:
Example: MyService.java
// MyService.java
package com.example.myapp.service;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@PostAuthorize("returnObject.owner == authentication.name")
public MyObject getObject() {
// Method logic
return new MyObject();
}
}
Using @Secured
The @Secured
annotation is used to specify one or more roles that are allowed to invoke a method:
Example: MyService.java
// MyService.java
package com.example.myapp.service;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@Secured("ROLE_ADMIN")
public void adminMethod() {
// Admin only logic
}
@Secured({"ROLE_USER", "ROLE_ADMIN"})
public void userOrAdminMethod() {
// User or Admin logic
}
}
Using @RolesAllowed
The @RolesAllowed
annotation is similar to @Secured
but uses standard JSR-250 annotations:
Example: MyService.java
// MyService.java
package com.example.myapp.service;
import javax.annotation.security.RolesAllowed;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@RolesAllowed("ROLE_ADMIN")
public void adminMethod() {
// Admin only logic
}
@RolesAllowed({"ROLE_USER", "ROLE_ADMIN"})
public void userOrAdminMethod() {
// User or Admin logic
}
}
Example: Full Configuration and Service
Here is a full example combining security configuration and service method annotations:
Example: SecurityConfiguration.java
// SecurityConfiguration.java
package com.example.myapp.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password(passwordEncoder().encode("password"))
.roles("USER")
.and()
.withUser("admin")
.password(passwordEncoder().encode("admin"))
.roles("ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Example: MyService.java
// MyService.java
package com.example.myapp.service;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@PreAuthorize("hasRole('ADMIN')")
public void adminMethod() {
// Admin only logic
}
@PreAuthorize("hasRole('USER')")
public void userMethod() {
// User only logic
}
@PostAuthorize("returnObject.owner == authentication.name")
public MyObject getObject() {
// Method logic
return new MyObject();
}
@Secured("ROLE_ADMIN")
public void securedAdminMethod() {
// Admin only logic
}
@Secured({"ROLE_USER", "ROLE_ADMIN"})
public void securedUserOrAdminMethod() {
// User or Admin logic
}
@RolesAllowed("ROLE_ADMIN")
public void rolesAllowedAdminMethod() {
// Admin only logic
}
@RolesAllowed({"ROLE_USER", "ROLE_ADMIN"})
public void rolesAllowedUserOrAdminMethod() {
// User or Admin logic
}
}
Key Points
- @EnableWebSecurity: Enables Spring Security’s web security support and provides the Spring MVC integration.
- @PreAuthorize: Specifies a method should be accessible only if the specified expression evaluates to true before the method is invoked.
- @PostAuthorize: Specifies a method should be accessible only if the specified expression evaluates to true after the method is invoked.
- @Secured: Specifies one or more roles that are allowed to invoke a method.
- @RolesAllowed: Similar to @Secured but uses standard JSR-250 annotations.
- @EnableGlobalMethodSecurity: Enables method-level security.
- Enable method-level security by adding the
@EnableGlobalMethodSecurity
annotation in your configuration class. - Use
@PreAuthorize
and@PostAuthorize
to secure methods with authorization expressions. - Use
@Secured
and@RolesAllowed
to specify roles that can invoke methods. - Combine security configuration and service method annotations to secure your Spring Boot application effectively.
Conclusion
Spring Security annotations provide a powerful and declarative way to secure methods in your Spring Boot applications. By understanding and using these annotations effectively, you can implement fine-grained security controls and ensure that your application is protected against unauthorized access. Happy coding!