0
0
SpringbootHow-ToBeginner · 4 min read

How to Use @PreAuthorize in Spring Boot for Method Security

Use @PreAuthorize in Spring Boot by enabling method security with @EnableMethodSecurity and annotating your service methods with expressions like @PreAuthorize("hasRole('ROLE_ADMIN')"). This restricts method access based on user roles or permissions before the method runs.
📐

Syntax

The @PreAuthorize annotation is placed above a method to define a security expression that must be true for the method to execute. It uses Spring Expression Language (SpEL) to check roles, permissions, or custom conditions.

  • @PreAuthorize("expression"): The expression defines the access rule.
  • Common expressions include hasRole('ROLE_NAME'), hasAuthority('AUTHORITY'), and principal.username == #username.
  • Enable method security in your configuration with @EnableMethodSecurity.
java
@EnableMethodSecurity
public class SecurityConfig {
    // Security configuration here
}

@Service
public class MyService {
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public void adminOnlyMethod() {
        // method logic
    }
}
💻

Example

This example shows a Spring Boot service with a method secured by @PreAuthorize to allow only users with the ADMIN role to access it. The security configuration enables method security.

java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.stereotype.Service;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
class SecurityConfig {
    public UserDetailsService userDetailsService() {
        var user = User.withDefaultPasswordEncoder()
            .username("admin")
            .password("password")
            .roles("ADMIN")
            .build();
        return new InMemoryUserDetailsManager(user);
    }
}

@Service
class MyService {
    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public String adminOnlyAction() {
        return "Access granted to admin method.";
    }
}
Output
Access granted to admin method.
⚠️

Common Pitfalls

  • Not enabling method security with @EnableMethodSecurity causes @PreAuthorize to be ignored.
  • Using hasRole('ADMIN') requires the role to be prefixed with ROLE_ internally, so the actual role should be ROLE_ADMIN.
  • Placing @PreAuthorize on private methods or methods called internally within the same class will not trigger security checks.
  • Incorrect SpEL syntax or missing quotes can cause runtime errors.
java
/* Wrong: Missing @EnableMethodSecurity disables @PreAuthorize */
@Configuration
class WrongConfig {
    // No @EnableMethodSecurity here
}

/* Right: Enable method security */
@Configuration
@EnableMethodSecurity
class RightConfig {
    // Correct setup
}
📊

Quick Reference

ExpressionDescriptionExample
hasRole('ROLE_NAME')Checks if user has a specific role@PreAuthorize("hasRole('ROLE_ADMIN')")
hasAuthority('AUTHORITY')Checks if user has a specific authority@PreAuthorize("hasAuthority('WRITE_PRIVILEGE')")
principal.username == #usernameChecks if the authenticated user's username matches method argument@PreAuthorize("principal.username == #username")
permitAll()Allows all users to access@PreAuthorize("permitAll()")
denyAll()Denies all users access@PreAuthorize("denyAll()")

Key Takeaways

Always enable method security with @EnableMethodSecurity to activate @PreAuthorize.
@PreAuthorize uses Spring Expression Language to define access rules before method execution.
Roles in hasRole() must be prefixed with ROLE_ internally, e.g., hasRole('ADMIN') checks for ROLE_ADMIN.
Security checks do not apply to private methods or internal calls within the same class.
Use clear and correct SpEL syntax to avoid runtime errors.