Spring Security at Method Level
Last Updated :
13 Sep, 2025
Spring Security provides a way to secure Java applications by controlling authentication and authorization at different levels. Beyond securing URLs and endpoints, one of its key features is method-level security, which allows developers to apply access restrictions directly on specific methods instead of securing the entire class or application.
Why Method-Level Security
- Granular Control: Restrict access to specific methods instead of the entire application or URL.
- Business Logic Protection: Even if someone bypasses the web layer, the service methods remain protected.
- Role-Based Access: Easily define role-based restrictions at the method level.
- Separation of Concerns: Security logic is applied declaratively without polluting business logic.
Enabling Method-Level Security
In Spring Security, method-level security is enabled using the @EnableMethodSecurity annotation instead of the deprecated @EnableGlobalMethodSecurity.
Java
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
// Other security configurations
}
Common Annotations for Method Security
Spring Security provides annotations to restrict access to methods based on roles and conditions:
1. @Secured
The @Secured annotation allows access control based on user roles.
Java
@Service
public class ReportService {
@Secured("ROLE_MANAGER")
public String generateReport() {
return "Report generated!";
}
}
Only users with the role ROLE_MANAGER can access generateReport().
2. @PreAuthorize
The @PreAuthorize annotation provides more flexibility by using Spring Expression Language (SpEL) for defining conditions.
Java
@Service
public class AccountService {
@PreAuthorize("hasRole('ADMIN')")
public String deleteAccount(Long id) {
return "Account " + id + " deleted!";
}
}
Only users with the role ROLE_ADMIN can execute the deleteAccount() method.
3. @PostAuthorize
The @PostAuthorize annotation is used to apply security constraints after the method execution for filtering return values.
Java
@Service
public class AccountService {
@PostAuthorize("returnObject.owner == authentication.name")
public Account getAccountDetails(Long id) {
// fetch account
return new Account(id, "john_doe");
}
}
Only the owner of the account can access the returned Account object.
4. @RolesAllowed
Standard JSR-250 annotation (requires @EnableMethodSecurity(jsr250Enabled = true)).
Java
@Service
public class UserService {
@RolesAllowed({"ROLE_ADMIN", "ROLE_USER"})
public String viewProfile() {
return "Profile details shown!";
}
}
Both ROLE_ADMIN and ROLE_USER can access viewProfile().
Step-by-Step Implementation of Spring Security at Method Level
Step 1: Create a Spring Boot Project
Create a project via Spring Initializr or directly in IntelliJ IDEA / STS.
Project Details:
- Project: Maven Project
- Spring Boot Version: 3.3.x
- Dependencies: Spring Web, Spring Security
pom.xml:
Java
<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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-security-method-level</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Spring Security Method Level</name>
<description>Demo project for Spring Security method-level security</description>
<!-- Spring Boot Parent -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<release>17</release>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Step 2: Enable Method-Level Security
Create a configuration class that is annoteted with @Configuration and @EnableMethodSecurity.
Java
package com.example.security.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableMethodSecurity // Enable method-level security
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.httpBasic(); // Using HTTP Basic authentication
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
var userDetailsManager = new InMemoryUserDetailsManager();
var user = User.withUsername("user")
.password(passwordEncoder().encode("user123"))
.roles("USER")
.build();
var admin = User.withUsername("admin")
.password(passwordEncoder().encode("admin123"))
.roles("ADMIN")
.build();
userDetailsManager.createUser(user);
userDetailsManager.createUser(admin);
return userDetailsManager;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Step 3: Create a Service with Method-Level Security
We will use @PreAuthorize to restrict access to methods based on roles.
Java
package com.example.security.service;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
public String getUserData() {
return "This is user data accessible by USER or ADMIN.";
}
@PreAuthorize("hasRole('ADMIN')")
public String getAdminData() {
return "This is admin data accessible only by ADMIN.";
}
}
Step 4: Create a Controller
Create a controller class for testing endpoint.
Java
package com.example.security.controller;
import com.example.security.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/user")
public String userAccess() {
return userService.getUserData();
}
@GetMapping("/admin")
public String adminAccess() {
return userService.getAdminData();
}
}
Step 5: Run and Test
Run the Spring Boot application.
Access endpoints with Basic Auth
Test 1:
http://localhost:8080/user
- Username: user
- Password: user123
userOutput:
outputTest 2:
http://localhost:8080/admin
- Username: admin
- Password: admin123
adminOutput:
output
Explore
Java Enterprise Edition
Multithreading
Concurrency
JDBC (Java Database Connectivity)
Java Frameworks
JUnit