Sécurité des méthodes avec SpEL et votants personnalisés
Appliquez un contrôle d’accès granulaire à l’aide de @PreAuthorize, des expressions SpEL et d’une logique d’autorisation personnalisée.
Sécurité des méthodes avec SpEL et votants personnalisés est une leçon Spring Boot 4 Complete Guide gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Spring Boot 4 Complete Guide, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Spring Boot 4 Complete Guide comprend 4 leçons au total.
Certaines parties de cette leçon n'ont pas encore été traduites et s'affichent en anglais.
Why Method Security?
URL-based security (HttpSecurity matchers) guards entry points, but it cannot see the arguments a method receives or the object it returns. Method security closes that gap by enforcing rules right at the service layer.
- Defense in depth — protection survives even if a controller forgets a check.
- Fine-grained — decide based on parameters, return values, and the authenticated principal.
- Reusable — the same secured service can be called from REST, GraphQL, or a message listener and stays protected.
In this lesson we enforce access with @PreAuthorize, SpEL expressions, and a custom authorization manager.
Enabling Method Security
In Spring Boot 4 / Spring Security 6, method security is opt-in. Add @EnableMethodSecurity to a configuration class. It activates the annotations through an AOP proxy.
prePostEnableddefaults to true —@PreAuthorizeand@PostAuthorizework out of the box.- Set
securedEnabled = truefor the legacy@Secured, orjsr250Enabled = truefor@RolesAllowed.
Note: the old @EnableGlobalMethodSecurity is removed — always use @EnableMethodSecurity.
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
@Configuration
@EnableMethodSecurity
public class MethodSecurityConfig {
// prePostEnabled = true by default
// @PreAuthorize / @PostAuthorize now active
}@PreAuthorize with Roles and Authorities
@PreAuthorize evaluates a SpEL expression before the method runs. If it returns false, Spring throws AccessDeniedException and the body never executes.
hasRole('ADMIN')— checks theROLE_ADMINauthority (the prefix is added for you).hasAuthority('SCOPE_orders:write')— exact authority match, no prefix added.hasAnyRole('ADMIN','MANAGER')and the boolean operatorsand/or/!.
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class AccountService {
@PreAuthorize("hasRole('ADMIN')")
public void closeAccount(Long accountId) {
// only ROLE_ADMIN reaches here
}
@PreAuthorize("hasAnyRole('ADMIN','SUPPORT') or hasAuthority('SCOPE_accounts:write')")
public void freezeAccount(Long accountId) {
// ...
}
}Referencing Method Arguments with #
The real power of SpEL is reading method arguments. Prefix a parameter name with # to use it inside the expression. This lets you compare the principal's identity to the data being acted on.
authentication— the currentAuthenticationobject.principal— the principal (often aUserDetailsor JWT).#username,#order.ownerId— method arguments and their properties.
Argument names require parameters compiled with -parameters (Spring Boot enables this by default).
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
@Service
public class ProfileService {
// A user may edit only their own profile, unless they are an admin
@PreAuthorize("#username == authentication.name or hasRole('ADMIN')")
public void updateProfile(String username, ProfileDto dto) {
// ...
}
}@PostAuthorize and returnObject
@PostAuthorize runs after the method returns and can inspect the result via returnObject. Use it when you must load the entity first to know who owns it.
- Good for “you can read this record only if it belongs to you.”
- The method body does execute, so avoid it for operations with side effects you must prevent.
- On denial, the return value is discarded and
AccessDeniedExceptionis thrown.
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.stereotype.Service;
@Service
public class DocumentService {
@PostAuthorize("returnObject.ownerUsername == authentication.name or hasRole('ADMIN')")
public Document findById(Long id) {
return repository.findById(id).orElseThrow();
}
}@PreFilter and @PostFilter on Collections
Filtering annotations prune collections element by element instead of throwing. They use a special variable filterObject bound to each element.
@PreFilter— strips disallowed elements from a collection argument before the method runs.@PostFilter— strips disallowed elements from the returned collection.- Use
filterTargetwhen a method has more than one collection parameter.
Caution: post-filtering large result sets in memory can be costly — prefer filtering in the query when possible.
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class OrderService {
// Caller sees only the orders they own (admins see all)
@PostFilter("filterObject.ownerUsername == authentication.name or hasRole('ADMIN')")
public List<Order> findRecentOrders() {
return repository.findRecent();
}
}Calling a Bean from SpEL with @
When logic gets complex, push it into a Spring bean and call it from the expression using @beanName.method(...). This keeps annotations readable and the rule unit-testable.
- The
@resolves a bean from the application context. - Pass
authenticationand method arguments straight into the bean method. - The method must return a
boolean.
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
@Component("projectAccess")
public class ProjectAccessEvaluator {
public boolean canEdit(Authentication auth, Long projectId) {
String user = auth.getName();
return membershipRepository.isEditor(user, projectId);
}
}
// Usage on a service method:
// @PreAuthorize("@projectAccess.canEdit(authentication, #projectId)")
// public void rename(Long projectId, String name) { ... }PermissionEvaluator and hasPermission
SpEL exposes hasPermission(target, permission), which delegates to a PermissionEvaluator bean. It is the canonical hook for domain-object (ACL-style) authorization without inlining logic in every annotation.
hasPermission(#doc, 'WRITE')— passes the object and a permission key.hasPermission(#id, 'com.app.Document', 'READ')— passes an id plus the type.- You register exactly one
PermissionEvaluatorvia aMethodSecurityExpressionHandler.
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import java.io.Serializable;
public class DocumentPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission(Authentication auth, Object target, Object permission) {
if (target instanceof Document doc) {
return "WRITE".equals(permission)
? doc.getOwnerUsername().equals(auth.getName())
: true; // READ allowed for all in this example
}
return false;
}
@Override
public boolean hasPermission(Authentication auth, Serializable id,
String type, Object permission) {
return false; // resolve by id+type if needed
}
}Registering a Custom Expression Handler
To wire your PermissionEvaluator into SpEL, expose a DefaultMethodSecurityExpressionHandler bean and set the evaluator on it. Spring Security picks it up for all method annotations.
- The bean name is not important; the type is.
- You can also attach a custom
RoleHierarchyhere sohasRolerespects inheritance.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
@Configuration
@EnableMethodSecurity
public class ExpressionHandlerConfig {
@Bean
static DefaultMethodSecurityExpressionHandler expressionHandler() {
var handler = new DefaultMethodSecurityExpressionHandler();
handler.setPermissionEvaluator(new DocumentPermissionEvaluator());
return handler;
}
}Custom AuthorizationManager (the New Voter)
Spring Security 6 replaced the legacy AccessDecisionVoter with the simpler AuthorizationManager<T>. For method security the type parameter is MethodInvocation. Implement check to return an AuthorizationDecision.
- Return
new AuthorizationDecision(true|false)— ornullto abstain and let other managers decide. - Register it with
@EnableMethodSecurity(prePostEnabled = false)plus an advisor, or combine managers withAuthorizationManagers.allOf(...).
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import java.util.function.Supplier;
public class BusinessHoursAuthorizationManager
implements AuthorizationManager<MethodInvocation> {
@Override
public AuthorizationDecision check(Supplier<Authentication> auth,
MethodInvocation invocation) {
int hour = java.time.LocalTime.now().getHour();
boolean withinHours = hour >= 9 && hour < 18;
return new AuthorizationDecision(withinHours);
}
}Pre vs Post: Choosing Correctly
Picking the wrong annotation either leaks data or blocks valid calls. A quick decision guide:
- Rule depends only on arguments + principal →
@PreAuthorize(fast, no side effects). - Rule depends on the loaded entity's ownership →
@PostAuthorize. - Trimming a collection per-element →
@PostFilter(or filter in the query). - Reusable domain-object rule →
hasPermission+PermissionEvaluator.
Remember: @PostAuthorize and @PostFilter run the method body, so never rely on them to stop a mutating operation.
Quick Check
You have a method Document findById(Long id) that loads a document, and access should be granted only if the returned document's ownerUsername equals the caller, or the caller is an admin. Which annotation expresses this correctly?
Recap
You now enforce fine-grained access at the method layer:
@EnableMethodSecurityturns on annotation-driven checks (no more@EnableGlobalMethodSecurity).@PreAuthorizeguards before execution using SpEL:hasRole,hasAuthority,#args, andauthentication.@PostAuthorizeinspectsreturnObject;@PreFilter/@PostFilterprune collections viafilterObject.- Push complex rules into a bean (
@beanName.method(...)) or aPermissionEvaluatorbehindhasPermission. - For cross-cutting policy, implement
AuthorizationManager<MethodInvocation>— the modern replacement for voters.
Rule of thumb: prefer pre-checks for speed and safety; reach for post-checks only when the decision needs the loaded data.
Apprends Java avec un tuteur IA — gratuit
Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.
- Cours
- 21
- Leçons
- 84
Questions Fréquemment Posées
La leçon « Sécurité des méthodes avec SpEL et votants personnalisés » est-elle gratuite ?
Oui — le texte complet de « Sécurité des méthodes avec SpEL et votants personnalisés » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Spring Boot 4 Complete Guide, passe à CoddyKit PRO. Le cours Spring Boot 4 Complete Guide comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Sécurité des méthodes avec SpEL et votants personnalisés » ?
Appliquez un contrôle d’accès granulaire à l’aide de @PreAuthorize, des expressions SpEL et d’une logique d’autorisation personnalisée. Tu pratiques Spring Boot 4 Complete Guide avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Spring Boot 4 Complete Guide ?
Aucune expérience préalable n'est requise. Spring Boot 4 Complete Guide sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « Sécurité des méthodes avec SpEL et votants personnalisés » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Spring Boot 4 Complete Guide ?
Oui. Chaque leçon Spring Boot 4 Complete Guide inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Validation des JWT du serveur de ressources et revendications
- Client OAuth2 et flux du code d’autorisation
- Sécurité des méthodes avec SpEL et votants personnalisés
- Introspection des jetons opaques et échange de jetons