security

Method Security & @PreAuthorize

Authorize at the method level using SpEL expressions — so business logic encodes the access rule next to the action.

URL-based authorisation is coarse: it secures an endpoint, but the real rule is often finer — "only an admin may delete," or "a user may edit only their own document." Method security pushes the access check down to the method itself, expressed as an annotation right where the protected action lives, so the authorisation rule sits next to the behaviour it guards rather than far away in a filter-chain configuration.

Library rules at the shelf, not just at the front door — "only researchers can access the rare books section" is checked when you reach for the shelf.

Key Concepts

1
After enabling it with @EnableMethodSecurity, you annotate service methods with @PreAuthorize, whose Spring Expression Language (SpEL) condition is evaluated before the method runs; if it is false, access is denied and the method never executes. The expressions can reference roles and authorities (hasRole('ADMIN')), the authenticated principal, and crucially the method's own arguments and return value — @PreAuthorize("#doc.ownerId == authentication.name") enforces ownership, and @PostAuthorize can even filter based on what the method returned. This makes it possible to encode genuinely contextual, data-dependent rules declaratively, layered on top of the coarse URL rules in the filter chain rather than replacing them.
@EnableMethodSecurity@PreAuthorizehasRole('ADMIN')@PreAuthorize("#doc.ownerId == authentication.name")@PostAuthorize
2
Because it is built on Spring AOP proxies, method security inherits the familiar proxy caveats: it applies to calls that pass through the proxy, so an internal self-invocation can bypass the check, and it targets Spring-managed beans. The design guidance interviewers look for is defence in depth — combine broad URL rules for the obvious cases with method-level rules for the fine-grained, data-aware ones — and keeping the SpEL expressions readable, extracting complex logic into a permission-evaluator component when a one-line expression starts to sprawl.