Spring Security @PreAuthorize Annotation for Method Security
Last Updated :
17 Oct, 2024
In Spring Security, the @PreAuthorize
annotation can apply method-level security by defining access control rules. It ensures that authorized users can only access specific functionalities before the method is invoked. This is especially useful in protecting sensitive operations such as CRUD methods, service methods, or business logic.
The @PreAuthorize
annotation works by checking the provided security expression before executing the method. If the user doesn't meet the specified condition, an AccessDeniedException
is thrown, preventing the method from running.
@PreAuthorize Annotation in Spring Security
The @PreAuthorize
annotation is a key mechanism for applying method-level security in Spring Security. It enables you to specify security constraints on methods, ensuring only authorized users can execute them. This can be useful when restricting access based on roles, permissions, or other user-specific attributes.
What is @PreAuthorize
?
The @PreAuthorize
annotation is part of Spring Security's method-level security framework. It allows you to apply security rules directly on methods in service or controller classes. These rules are written using SpEL (Spring Expression Language), which helps you specify conditions based on user roles, authentication status, or other attributes.
When a method annotated with @PreAuthorize
is called, Spring Security checks if the condition specified in the annotation is true for the current user. If the condition isn't met, an AccessDeniedException
is thrown.
Example Signature of @PreAuthorize
:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PreAuthorize {
String value();
}
The value
attribute takes a SpEL expression that defines the security condition to be met before the method is invoked.
SpEL (Spring Expression Language) in @PreAuthorize
SpEL is a powerful tool for evaluating expressions in Spring. When used with @PreAuthorize
, it lets you create security rules based on:
- Roles: Checking if the user has specific roles.
- Authorities: Checking specific permissions granted to the user.
- Authentication status: Checking if the user is authenticated or anonymous.
- Custom conditions: Defining logic based on method parameters or user details.
How @PreAuthorize
Works
When a method annotated with @PreAuthorize
is invoked, Spring Security intercepts the call and evaluates the condition specified in the annotation. The flow is as follows:
- User Authentication: Spring Security checks if the user is authenticated.
- Expression Evaluation: The SpEL expression in
@PreAuthorize
is evaluated against the user’s authentication details (roles, authorities, etc.). - Access Decision:
- If the expression evaluates to
true
, the method is executed. - If the expression evaluates to
false
, an AccessDeniedException
is thrown, preventing the method from executing.
Implementation of @PreAuthorize
for Method Security
Let's implement the @PreAuthorize
annotation in a Spring Boot application to secure a REST API method.
Step 1: Create a New Spring Boot Project
Create a new Spring Boot project in IntelliJ IDEA with the following options:
- Name:
spring-security-preauthorize
- Language: Java
- Type: Maven
- Packaging: Jar
Click on the Next button.
Step 2: Add the Dependencies
Add the following dependencies into the Spring Boot project.
- Spring Web
- Spring Security
- Lombok
- Spring Boot DevTools
Click on the Create button.
Project Structure
After the project creation done, the folder structure will look like the below image:
Step 3: Configure Application Properties
Add the following to the application.properties
file:
spring.application.name=spring-security-preauthorize
Step 4: Create the User
Class
Java
package com.gfg.springsecuritypreauthorize;
// Class that represents a user with ID, username, and role fields
public class User {
private Long id;
private String username;
private String role;
// Constructor to initialize user details
public User(Long id, String username, String role) {
this.id = id;
this.username = username;
this.role = role;
}
// Getters to retrieve user details
public Long getId() {
return id;
}
public String getUsername() {
return username;
}
public String getRole() {
return role;
}
}
This class defines the User
object with fields such as id
, username
, and role
. The constructor initializes these fields, and the getter methods provide access to them.
Step 5: Create the UserService
Class
Java
package com.gfg.springsecuritypreauthorize;
import org.springframework.stereotype.Service;
@Service
public class UserService {
// Method that returns a mock user for demonstration
public User getUser() {
return new User(1L, "John Doe", "ROLE_USER");
}
}
The UserService
class contains a method that returns a mock user object. In a real-world application, this service would fetch the user details from a database or another data source.
Step 6: Create the SecurityConfig
Class
Java
package com.gfg.springsecuritypreauthorize;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true) // Enable method-level security
public class SecurityConfig {
// Configure the security filter chain
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable() // Disable CSRF for simplicity
.authorizeRequests()
.requestMatchers("/user").hasRole("USER") // Secure /user endpoint
.anyRequest().authenticated() // Any other request must be authenticated
.and()
.httpBasic(); // Use Basic Authentication
return http.build();
}
// Configure an in-memory authentication manager
@Bean
public AuthenticationManager authManager(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder =
http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder
.inMemoryAuthentication()
.withUser("user").password(passwordEncoder().encode("password")).roles("USER");
return authenticationManagerBuilder.build();
}
// Using BCrypt for password encoding
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
The SecurityConfig
class configures Spring Security. It enables method-level security with @EnableMethodSecurity(prePostEnabled = true)
and secures the /user
endpoint so only users with the ROLE_USER
can access it. An in-memory authentication manager is set up, and passwords are encoded using BCrypt.
Step 7: Create the UserController
Class
Java
package com.gfg.springsecuritypreauthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Autowired
private UserService userService;
// this method is accessible only to users with the ROLE_USER
@PreAuthorize("hasRole('ROLE_USER')")
@GetMapping("/user")
public User getUser() {
return userService.getUser();
}
}
The UserController
class defines an API endpoint /user
. The method getUser()
is secured with the @PreAuthorize
annotation, which ensures that only users with the role ROLE_USER
can access this method.
Step 8: Main class
Java
package com.gfg.springsecuritypreauthorize;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringSecurityPreauthorizeApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSecurityPreauthorizeApplication.class, args);
}
}
pom.xml File:
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gfg</groupId>
<artifactId>spring-security-preauthorize</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-security-preauthorize</name>
<description>spring-security-preauthorize</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 9: Run the Application
After completing the project, run the application and it will run on port 8080.
Step 10: Testing the Application
Now, we will test the endpoints using the postman tool.
GET http://localhost:8080/user
Response:
In this implementation, we demonstrated how to use the @PreAuthorize annotation to secure a method in the Spring Boot application based on the user roles.
Similar Reads
Spring Security â Customizing Authentication and Authorization Spring Security is the powerful and customizable framework that provides the authentication, authorization, and other security features for the Java applications, especially the Spring-based ones. When building secure applications, controlling access to resources is important. Customizing authorizat
7 min read
Spring Security Custom AuthenticationFailureHandler In Java, Spring Security is a very powerful framework that can provide comprehensive security services for Java enterprise software applications. One of the essential aspects of the security is authentication and it can be users are verified before granting access to the resource. Spring Security ca
6 min read
Spring Security Annotations There are multiple annotations supported by Spring Security. But, in this article, we will discuss about these annotations can be used in a Spring Boot project as well. These annotations play a crucial role in creating a web application in Spring Boot. The Spring Security annotations are a powerful
3 min read
Spring Security - security none, filters none, access permitAll In Spring Boot, Spring Security is the most powerful authentication and access control framework for Java applications. Spring Security provides strong security features to protect our web applications from various security threats such as authentication, authorization, session management, and web v
6 min read
Spring Security - In-Memory Authentication Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications. Spring Security is a framework that focuses on providing both authentication and authorization to Java applications. Like all Spring
4 min read