In this Spring Security tutorial, you will learn how to use the @PreAuthorize annotation to secure method invocation. You can use the @PreAuthorize annotation to secure either method in a Controller class or a method in a service layer class.
There are other useful method-level security annotations like the ones below. It is useful to know how they work as well.
- @PostAuthorize Security Annotation Example,
- @Secured Security Annotation Example,
- Spring Method Security: Customize Error Message.
If you are interested in video lessons, then I also show how to create user Roles and Authorities and how to use Spring Method Level Security annotations in my video course: RESTful Web Services, Spring Boot, Spring MVC, and JPA.
To be able to use Spring Method Security, you will first need to add Spring Security dependency to a pom.xml file of your Spring Boot application. Below is an example of how to do it.
Add Spring Security Dependency
To enable Spring Security in your Spring Boot application, open the pom.xml file and add the following dependency:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
Configure Roles and Authorities
The Spring Method Level security is used in Spring Boot applications that have user Roles and Authorities configured. If your Spring Boot application does not have Roles or Authorities configured yet, below are a few tutorials that can help you learn how to enable Basic Authentication and configure Roles and Authorities.
- Spring Security HTTP Basic In-Memory Authentication,
- Spring Security – Configure default Username, Password, and a Role,
- Spring Security – Secure RestController methods with Method-Level Security,
- Add H2 Database to Spring Boot Project with Spring Security ( Includes video tutorials )
- Spring Security – Get the Currently Authenticated Principal User Details
Enable @PreAuthorize Annotation
To enable @PreAuthorize and also @PostAuthorize annotations in your Spring Boot application you will need to first enable the Global Method Security. To enable the Global Method Security, add the @EnableGlobalMethodSecurity annotation to any Java class in your application which has the @Configuration annotation. If your application has Spring Security enabled and at least a Basic Authentication configured, then you can add the @EnableGlobalMethodSecurity annotation and enable method level security in a class that configures HTTPSecurity and is annotated with @EnableWebSecurity annotation. For example:
@EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurity extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // Some code here } }
Notice the use of prePostEnabled=true in @EnableGlobalMethodSecurity annotation. The prePostEnabled=true is what enables the @PreAuthorize and also @PostAuthorize annotations.
Now when you have Spring Security enabled, Roles and Authorities configured and you have also enabled Global Method Security, you can use the @PreAuthorize annotation on a method level and restrict access to some web service endpoints or business methods to specific user Role and Authorities.
Using the @PreAuthorize Annotation
@PreAuthorize annotation is used on a method level. For example, you can add the @PreAuthorize annotation above the @RequestMapping method that handles HTTP DELETE requests to allow only those users who have an ADMIN Role to invoke this method.
@PreAuthorize annotation supports method security expressions. The business logic in a method annotation with @PreAuthorize annotation will not be executed unless security expression validation allows so. Let’s have a look at a couple of security expressions.
HasRole()
When using the hasRole() security expression, the prefix ROLE_ is skipped. This is because Spring Framework will add the prefix automatically for us.
@PreAuthorize("hasRole('ADMIN')")
HasAnyRole()
When you need to support multiple roles, you can use the hasAnyRole() expression.
@PreAuthorize("hasAnyRole('ADMIN','DB-ADMIN')")
HasAuthority()
@PreAuthorize annotation can also be used with hasAuthority(). When using hasAuthority() expression, you will need to provide a complete authority name.
@PreAuthorize("hasAuthority('DELETE_AUTHORITY')")
or
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
HasAnyAuthority()
When you need to support multiple authorities, hasAnyAuthority() expression can be used.
@PreAuthorize("hasAnyAuthority('DELETE_AUTHORITY', 'UPDATE_AUTHORITY')")
Below is a code example of @PreAuthorize annotation used above the method that handles the HTTP DELETE request.
@PreAuthorize("hasAuthority('DELETE_AUTHORITY')) @DeleteMapping(path = "/{id}", produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }) @Transactional public OperationStatusModel deleteUser(@PathVariable String id) { OperationStatusModel returnValue = new OperationStatusModel(); // Some code here return returnValue; }
Example of @PreAuthorize annotation accessing the principal object.
@PreAuthorize("hasRole('ADMIN') or principal.userId == #id") @DeleteMapping(path = "/{id}", produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }) @Transactional public OperationStatusModel deleteUser(@PathVariable String id) { OperationStatusModel returnValue = new OperationStatusModel(); // Some code here return returnValue; }
I hope this short tutorial was of some aid to you!
If you are interested to learn how other security annotations work, then have a look at the following tutorials:
Happy learning! 🙋🏻♂️