docs
Method security provides fine-grained authorization control at the method level using annotations and AOP interceptors. This comprehensive framework supports pre/post authorization, filtering, and custom authorization handlers.
Core Capabilities:
@PreAuthorize, @PostAuthorize, @PreFilter, @PostFilter, @Secured, @AuthorizeReturnObjectMethodInterceptor implementations@HandleAuthorizationDeniedKey Interfaces and Classes:
AuthorizationManagerBeforeMethodInterceptor - Pre-authorization interceptor (factory methods: preAuthorize(), secured(), jsr250())AuthorizationManagerAfterMethodInterceptor - Post-authorization interceptor (factory method: postAuthorize())PreFilterAuthorizationMethodInterceptor - Filters method parameters before invocationPostFilterAuthorizationMethodInterceptor - Filters return values after invocationAuthorizeReturnObjectMethodInterceptor - Applies authorization to returned objectsPreAuthorizeAuthorizationManager - Evaluates @PreAuthorize SpEL expressionsPostAuthorizeAuthorizationManager - Evaluates @PostAuthorize SpEL expressionsSecuredAuthorizationManager - Handles @Secured annotationsJsr250AuthorizationManager - Handles JSR-250 annotations (requires jakarta.annotation-api dependency)MethodAuthorizationDeniedHandler - Interface for custom denial handlingDefault Behaviors:
@PreAuthorize - Expression must evaluate to true for method to execute@PostAuthorize - Expression evaluated after method execution with access to returnObject@PreFilter - Filters collection parameters before method execution (uses filterObject variable)@PostFilter - Filters returned collections after method execution@Secured - Requires any one of the specified roles/authorities@AuthorizeReturnObject - Creates proxy on return value enforcing method-level securityThrowingMethodAuthorizationDeniedHandler (throws AuthorizationDeniedException)AuthorizationInterceptorsOrder enumThreading Model:
Mono / Flux for non-blocking executionLifecycle:
PointcutAdvisor)@Bean methods returning AdvisorExceptions:
AuthorizationDeniedException - Thrown when authorization denied (default behavior)NullReturningMethodAuthorizationDeniedHandler - Returns null instead of throwing (since 6.5)Edge Cases:
#paramName (requires parameter name discovery)@PostAuthorize via returnObject variable@PreFilter / @PostFilter work on Collections and ArraysfilterTarget attribute in @PreFilter to specify which parameter@PostAuthorize expressions must handle null returnObject@AuthorizeReturnObject requires AuthorizationProxyFactory beanjakarta.annotation-api dependency for @RolesAllowed, @PermitAll, @DenyAllMethodSecurityExpressionHandler (default: DefaultMethodSecurityExpressionHandler)Evaluates a SpEL expression before method execution to determine if the invocation should proceed.
@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(String username) {
// Method execution
}Annotation Definition:
@PreAuthorize(String value){ .api }
Evaluates a SpEL expression after method execution, with access to the return value via returnObject.
@PostAuthorize("returnObject.owner == authentication.name")
public Document getDocument(Long id) {
return documentRepository.findById(id);
}Annotation Definition:
@PostAuthorize(String value){ .api }
returnObject, authentication, method parametersFilters a collection parameter before method execution based on a SpEL expression.
@PreFilter(value = "filterObject.owner == authentication.name",
filterTarget = "documents")
public void processDocuments(List<Document> documents) {
// Only documents owned by current user are processed
}Annotation Definition:
@PreFilter(String value, String filterTarget = ""){ .api }
Filters the returned collection after method execution.
@PostFilter("filterObject.isPublic or filterObject.owner == authentication.name")
public List<Document> getAllDocuments() {
return documentRepository.findAll();
}Annotation Definition:
@PostFilter(String value){ .api }
Legacy annotation specifying required security attributes (roles or authorities).
@Secured({"ROLE_ADMIN", "ROLE_MODERATOR"})
public void moderateContent() {
// Method execution
}Annotation Definition:
@Secured(String[] value){ .api }
Applies authorization to the returned object, creating a proxy that enforces method-level security on the return value.
@AuthorizeReturnObject
public UserService getUserService() {
return new UserServiceImpl();
}Annotation Definition:
@AuthorizeReturnObject{ .api }
Specifies a custom handler when authorization is denied, instead of throwing an exception.
@PreAuthorize("hasRole('ADMIN')")
@HandleAuthorizationDenied(handlerClass = MyDeniedHandler.class)
public Document getDocument(Long id) {
return documentRepository.findById(id);
}Annotation Definition:
@HandleAuthorizationDenied(
Class<? extends MethodAuthorizationDeniedHandler> handlerClass = void.class,
String handlerMethod = ""
){ .api }
MethodAuthorizationDeniedHandlerPre-authorization interceptor that evaluates authorization before method invocation.
public class AuthorizationManagerBeforeMethodInterceptor
implements MethodInterceptor, PointcutAdvisor{ .api }
Static Factory Methods:
static AuthorizationManagerBeforeMethodInterceptor preAuthorize(){ .api }
Creates interceptor for @PreAuthorize annotations.
static AuthorizationManagerBeforeMethodInterceptor preAuthorize(
AuthorizationManager<MethodInvocation> authorizationManager
){ .api }
Creates interceptor with custom authorization manager.
static AuthorizationManagerBeforeMethodInterceptor secured(){ .api }
Creates interceptor for @Secured annotations.
static AuthorizationManagerBeforeMethodInterceptor jsr250(){ .api }
Creates interceptor for JSR-250 annotations (@RolesAllowed, @PermitAll, @DenyAll).
Example Configuration:
@Bean
public Advisor preAuthorizeAdvisor() {
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize();
}Post-authorization interceptor that evaluates authorization after method completion.
public class AuthorizationManagerAfterMethodInterceptor
implements MethodInterceptor, PointcutAdvisor{ .api }
Static Factory Methods:
static AuthorizationManagerAfterMethodInterceptor postAuthorize(){ .api }
Creates interceptor for @PostAuthorize annotations.
static AuthorizationManagerAfterMethodInterceptor postAuthorize(
AuthorizationManager<MethodInvocationResult> authorizationManager
){ .api }
Creates interceptor with custom authorization manager.
Filters method parameters before invocation based on @PreFilter annotations.
public class PreFilterAuthorizationMethodInterceptor
implements MethodInterceptor, PointcutAdvisor{ .api }
Usage:
@Bean
public Advisor preFilterAdvisor() {
return new PreFilterAuthorizationMethodInterceptor();
}Filters method return values after invocation based on @PostFilter annotations.
public class PostFilterAuthorizationMethodInterceptor
implements MethodInterceptor, PointcutAdvisor{ .api }
Usage:
@Bean
public Advisor postFilterAdvisor() {
return new PostFilterAuthorizationMethodInterceptor();
}Applies authorization to returned objects based on @AuthorizeReturnObject annotation.
public class AuthorizeReturnObjectMethodInterceptor
implements MethodInterceptor, PointcutAdvisor{ .api }
Usage:
@Bean
public Advisor authorizeReturnObjectAdvisor(
AuthorizationProxyFactory proxyFactory
) {
return new AuthorizeReturnObjectMethodInterceptor(proxyFactory);
}Reactive pre-authorization interceptor for non-blocking operations.
public class AuthorizationManagerBeforeReactiveMethodInterceptor
implements MethodInterceptor, PointcutAdvisor{ .api }
Static Factory Methods:
static AuthorizationManagerBeforeReactiveMethodInterceptor preAuthorize(){ .api }
static AuthorizationManagerBeforeReactiveMethodInterceptor secured(){ .api }
static AuthorizationManagerBeforeReactiveMethodInterceptor jsr250(){ .api }
Reactive post-authorization interceptor.
public class AuthorizationManagerAfterReactiveMethodInterceptor
implements MethodInterceptor, PointcutAdvisor{ .api }
Reactive pre-filter interceptor.
public class PreFilterAuthorizationReactiveMethodInterceptor
implements MethodInterceptor, PointcutAdvisor{ .api }
Reactive post-filter interceptor.
public class PostFilterAuthorizationReactiveMethodInterceptor
implements MethodInterceptor, PointcutAdvisor{ .api }
Authorization manager for @PreAuthorize annotations, evaluating SpEL expressions.
public class PreAuthorizeAuthorizationManager
implements AuthorizationManager<MethodInvocation>{ .api }
Key Methods:
void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler){ .api }
Sets custom expression handler for SpEL evaluation.
Authorization manager for @PostAuthorize annotations.
public class PostAuthorizeAuthorizationManager
implements AuthorizationManager<MethodInvocationResult>{ .api }
Key Methods:
void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler){ .api }
Authorization manager for @Secured annotations.
public class SecuredAuthorizationManager
implements AuthorizationManager<MethodInvocation>{ .api }
Example:
@Bean
public SecuredAuthorizationManager securedAuthorizationManager() {
return new SecuredAuthorizationManager();
}Authorization manager for JSR-250 annotations (@RolesAllowed, @PermitAll, @DenyAll).
public class Jsr250AuthorizationManager
implements AuthorizationManager<MethodInvocation>{ .api }
Example:
@Bean
public Jsr250AuthorizationManager jsr250AuthorizationManager() {
return new Jsr250AuthorizationManager();
}Generic authorization manager using SpEL expressions for method security.
public class MethodExpressionAuthorizationManager
implements AuthorizationManager<MethodInvocation>{ .api }
Usage:
MethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
MethodExpressionAuthorizationManager manager =
new MethodExpressionAuthorizationManager(handler, "hasRole('ADMIN')");PreAuthorizeReactiveAuthorizationManager:
public class PreAuthorizeReactiveAuthorizationManager
implements ReactiveAuthorizationManager<MethodInvocation>{ .api }
PostAuthorizeReactiveAuthorizationManager:
public class PostAuthorizeReactiveAuthorizationManager
implements ReactiveAuthorizationManager<MethodInvocationResult>{ .api }
Interface for handling authorization denials at method level.
public interface MethodAuthorizationDeniedHandler{ .api }
Key Methods:
Object handleDeniedInvocation(
MethodInvocation methodInvocation,
AuthorizationResult authorizationResult
){ .api }
Handles denied invocation before method execution.
Object handleDeniedInvocationResult(
MethodInvocationResult methodInvocationResult,
AuthorizationResult authorizationResult
){ .api }
Handles denied invocation after method execution.
Returns null when authorization is denied instead of throwing exception.
public class NullReturningMethodAuthorizationDeniedHandler
implements MethodAuthorizationDeniedHandler{ .api }
Example:
@PreAuthorize("hasRole('ADMIN')")
@HandleAuthorizationDenied(handlerClass = NullReturningMethodAuthorizationDeniedHandler.class)
public Document getDocument(Long id) {
return documentRepository.findById(id);
}
// Returns null instead of throwing AccessDeniedExceptionInvokes a specified method when authorization is denied, allowing custom fallback logic.
public class ReflectiveMethodAuthorizationDeniedHandler
implements MethodAuthorizationDeniedHandler{ .api }
Example:
public class DocumentService {
@PreAuthorize("hasRole('ADMIN')")
@HandleAuthorizationDenied(handlerClass = ReflectiveMethodAuthorizationDeniedHandler.class,
handlerMethod = "handleDenied")
public Document getDocument(Long id) {
return documentRepository.findById(id);
}
private Document handleDenied(MethodInvocation invocation,
AuthorizationResult result) {
return Document.publicPlaceholder();
}
}Represents the result of a method invocation for post-authorization checks.
public class MethodInvocationResult{ .api }
Key Methods:
MethodInvocation getMethodInvocation(){ .api }
Returns the original method invocation.
Object getResult(){ .api }
Returns the result of the method execution.
Example:
MethodInvocationResult result = new MethodInvocationResult(invocation, returnValue);
AuthorizationResult decision = postAuthManager.authorize(auth, result);Marker interface indicating an object is an authorization proxy.
public interface AuthorizationProxy{ .api }
Key Methods:
Object __AUTHORIZE__(){ .api }
Triggers authorization checks on the proxied object.
Creates authorization proxies using Spring AOP advisors.
public class AuthorizationAdvisorProxyFactory
implements AuthorizationProxyFactory{ .api }
Usage:
AuthorizationAdvisorProxyFactory factory = new AuthorizationAdvisorProxyFactory();
factory.setAdvisors(preAuthorizeAdvisor, postAuthorizeAdvisor);
UserService proxiedService = (UserService) factory.proxy(
userService,
UserService.class
);Defines the order of authorization interceptors.
public class AuthorizationInterceptorsOrder{ .api }
Constants:
int PRE_AUTHORIZE
int PRE_FILTER
int POST_AUTHORIZE
int POST_FILTER
int SECURED
int JSR250{ .api }
Usage:
@Bean
@Order(AuthorizationInterceptorsOrder.PRE_AUTHORIZE)
public Advisor preAuthorizeAdvisor() {
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize();
}Utility for creating pointcuts for method security annotations.
public class AuthorizationMethodPointcuts{ .api }
Static Methods:
static Pointcut forAnnotations(Class<? extends Annotation>... annotations){ .api }
Creates a pointcut matching methods with specified annotations.
Example:
Pointcut pointcut = AuthorizationMethodPointcuts.forAnnotations(
PreAuthorize.class,
PostAuthorize.class
);No-operation authorization event publisher for method security.
public class NoOpAuthorizationEventPublisher
implements AuthorizationEventPublisher{ .api }
Usage:
@Bean
public AuthorizationEventPublisher noOpEventPublisher() {
return new NoOpAuthorizationEventPublisher();
}Interface for creating and evaluating security expressions in method security context.
public interface MethodSecurityExpressionHandler
extends SecurityExpressionHandler<MethodInvocation>{ .api }
Key Methods:
Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx){ .api }
Filters a collection based on the expression.
void setReturnObject(Object returnObject, EvaluationContext ctx){ .api }
Sets the return object in the evaluation context for post-authorization.
Default implementation of method security expression handling.
public class DefaultMethodSecurityExpressionHandler
extends AbstractSecurityExpressionHandler
implements MethodSecurityExpressionHandler{ .api }
Key Methods:
void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer){ .api }
Sets the strategy for discovering parameter names.
void setTrustResolver(AuthenticationTrustResolver trustResolver){ .api }
Sets the trust resolver for evaluating authentication types.
Example Configuration:
@Bean
public DefaultMethodSecurityExpressionHandler methodSecurityExpressionHandler() {
DefaultMethodSecurityExpressionHandler handler =
new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(new CustomPermissionEvaluator());
handler.setRoleHierarchy(roleHierarchy());
handler.setDefaultRolePrefix("ROLE_");
return handler;
}Interface defining operations available in method security SpEL expressions.
public interface MethodSecurityExpressionOperations
extends SecurityExpressionOperations{ .api }
Available in Expressions:
authentication - Current Authentication objectprincipal - Principal from authenticationhasRole(String) - Check for rolehasAuthority(String) - Check for authorityhasPermission(Object, Object) - Permission checkfilterObject - Current object in filter expressionreturnObject - Method return value in post-authorizationRoot object for method security expression evaluation.
public class MethodSecurityExpressionRoot
extends SecurityExpressionRoot
implements MethodSecurityExpressionOperations{ .api }
Expression Variables:
@PreAuthorize("hasRole('ADMIN') or #username == authentication.name")
public void updateUser(String username, User user) {
// Method parameters accessible via #paramName
}
@PostAuthorize("returnObject.owner == authentication.name")
public Document getDocument(Long id) {
// returnObject available after execution
}
@PreFilter("filterObject.isActive()")
public void processUsers(List<User> users) {
// filterObject represents each collection element
}Evaluation context for method security expressions with lazy variable resolution.
public class MethodSecurityEvaluationContext extends StandardEvaluationContext{ .api }
Features:
@Configuration
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class MethodSecurityConfig {
@Bean
public DefaultMethodSecurityExpressionHandler expressionHandler() {
DefaultMethodSecurityExpressionHandler handler =
new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(permissionEvaluator());
handler.setRoleHierarchy(roleHierarchy());
return handler;
}
@Bean
public PermissionEvaluator permissionEvaluator() {
return new CustomPermissionEvaluator();
}
@Bean
public RoleHierarchy roleHierarchy() {
return RoleHierarchyImpl.withDefaultRolePrefix()
.role("ADMIN").implies("USER")
.role("USER").implies("GUEST")
.build();
}
}
@Service
public class SecuredService {
@PreAuthorize("hasRole('ADMIN')")
public void adminOnly() {
// Admin-only operation
}
@PreAuthorize("#username == authentication.name or hasRole('ADMIN')")
public User getUser(String username) {
return userRepository.findByUsername(username);
}
@PostAuthorize("returnObject.owner == authentication.name")
public Document getDocument(Long id) {
return documentRepository.findById(id);
}
@PreFilter("filterObject.isPublic or filterObject.owner == authentication.name")
@PostFilter("hasPermission(filterObject, 'READ')")
public List<Document> getDocuments(List<Long> ids) {
return documentRepository.findAllById(ids);
}
@PreAuthorize("hasRole('USER')")
@HandleAuthorizationDenied(handlerClass = NullReturningMethodAuthorizationDeniedHandler.class)
public Document getOptionalDocument(Long id) {
return documentRepository.findById(id);
}
}org.springframework.security.authorization.method