Method-Level Security with @PreAuthorize and @Secured in Spring Boot

When building secure applications, it’s not just about securing endpointsβ€”you often need to protect individual methods too. Spring Security provides powerful tools to implement method-level security, primarily using the annotations @PreAuthorize, @PostAuthorize, and @Secured. We’ll walk through how to enable and use Method-Level Security with @PreAuthorize and @Secured in Spring Boot application using the package com.kscodes.springboot.security.

In this tutorial, we’ll focus on the two most commonly used annotations in Spring Boot applications:

  • @PreAuthorize
  • @Secured

Method-Level Security with @PreAuthorize and @Secured in Spring Boot

πŸ“Œ What is Method-Level Security?

Method-level security allows you to apply access restrictions directly on methods in your codebase, usually in service or controller layers.
This means users will only execute a method if they meet certain authentication or role requirements.

βš™οΈ Enable Method-Level Security

To begin using @PreAuthorize or @Secured, you need to enable method security in your Spring Boot configuration class.

βœ… Add to SecurityConfig.java


package com.kscodes.springboot.security.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;

@Configuration
@EnableMethodSecurity(
    securedEnabled = true,         // Enables @Secured
    prePostEnabled = true          // Enables @PreAuthorize, @PostAuthorize
)
public class SecurityConfig {
    // Additional security config (like filterChain) can go here
}

πŸ”‘ Using @Secured

The @Secured annotation is simple and works well for role-based access control (RBAC).

🎯 Example: Service Layer


package com.kscodes.springboot.security.service;

import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Service;

@Service
public class AdminService {

    @Secured("ROLE_ADMIN")
    public String getAdminDashboard() {
        return "Admin dashboard data.";
    }

    @Secured({"ROLE_ADMIN", "ROLE_MANAGER"})
    public String getReports() {
        return "Accessing reports for admins and managers.";
    }
}

βœ… Note: Roles must be prefixed with "ROLE_". Spring Security automatically adds this prefix to authorities unless you override it.

🧠 Using @PreAuthorize

@PreAuthorize supports SpEL (Spring Expression Language) and gives you more flexibility.

🎯 Example: Controller with Conditions


package com.kscodes.springboot.security.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/user")
public class UserController {

    @PreAuthorize("hasRole('ADMIN')")
    @GetMapping("/admin-data")
    public String getAdminData() {
        return "Only accessible by ADMIN role.";
    }

    @PreAuthorize("hasAnyRole('USER', 'ADMIN')")
    @GetMapping("/common-data")
    public String getCommonData() {
        return "Accessible by USER and ADMIN roles.";
    }

    @PreAuthorize("#username == authentication.name")
    @GetMapping("/profile/{username}")
    public String getUserProfile(@PathVariable String username) {
        return "Profile data for user: " + username;
    }
}

πŸ’‘ Bonus: Method with Custom Condition


@PreAuthorize("hasAuthority('UPDATE_PRIVILEGE') and #id == authentication.principal.id")
public void updateUser(long id) {
    // Only if user has the update privilege and owns the ID
}

πŸ§ͺ SecurityContext Test Example

When writing tests or debugging method-level security, you can mock authentication like this:


@WithMockUser(roles = "ADMIN")
@Test
void testAdminOnlyMethod() {
    String result = adminService.getAdminDashboard();
    assertEquals("Admin dashboard data.", result);
}

βš–οΈ Comparison: @Secured vs @PreAuthorize

Feature@Secured@PreAuthorize
Role prefix requiredβœ… Yes (ROLE_)❌ Optional (can use hasRole or hasAuthority)
Supports SpEL❌ Noβœ… Yes
Multiple rolesβœ… With arrayβœ… With hasAnyRole()
Fine-grained logicβŒβœ… (e.g. match usernames, attributes)

βœ… Summary

  • Method-Level Security with @PreAuthorize and @Secured gives precise access control in Spring Boot applications.
  • Use @Secured for simple role-based rules.
  • Use @PreAuthorize for complex, conditional logic using Spring Expression Language.
  • Don’t forget to annotate your config with @EnableMethodSecurity.

πŸ”— Useful References