SpEL ve Özel Oylayıcılarla Metot Güvenliği
@PreAuthorize, SpEL ifadeleri ve özel yetkilendirme mantığıyla ayrıntılı erişim denetimi uygulayın.
SpEL ve Özel Oylayıcılarla Metot Güvenliği, CoddyKit'te ücretsiz bir Spring Boot 4 Complete Guide dersidir. Bu, 4 dersinin 3. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, Spring Boot 4 Complete Guide öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. Spring Boot 4 Complete Guide kursu toplamda 4 dersten oluşur.
Bu dersin bazı bölümleri henüz çevrilmemiş olup İngilizce olarak gösterilmektedir.
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.
Sıkça Sorulan Sorular
“SpEL ve Özel Oylayıcılarla Metot Güvenliği” dersi ücretsiz mi?
Evet — “SpEL ve Özel Oylayıcılarla Metot Güvenliği” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve Spring Boot 4 Complete Guide kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. Spring Boot 4 Complete Guide kursu toplamda 4 dersten oluşur.
“SpEL ve Özel Oylayıcılarla Metot Güvenliği” dersinde ne öğreneceğim?
@PreAuthorize, SpEL ifadeleri ve özel yetkilendirme mantığıyla ayrıntılı erişim denetimi uygulayın. Spring Boot 4 Complete Guide ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
Spring Boot 4 Complete Guide öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te Spring Boot 4 Complete Guide, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 3. dersidir.
“SpEL ve Özel Oylayıcılarla Metot Güvenliği” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu Spring Boot 4 Complete Guide dersinde kod yazıp çalıştırabilir miyim?
Evet. Her Spring Boot 4 Complete Guide dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- Kaynak Sunucusu JWT Doğrulaması ve Talepler
- OAuth2 İstemcisi ve Yetkilendirme Kodu Akışı
- SpEL ve Özel Oylayıcılarla Metot Güvenliği
- Opak Belirteç İncelemesi ve Belirteç Değişimi