Spring Expression Language enables fine-grained access control by letting security annotations evaluate runtime expressions—referencing the current user, method arguments, or bean methods—rather than being limited to static role names.
Key Points: • @PreAuthorize("hasRole('ADMIN') and #order.ownerId == authentication.principal.id") combines role and ownership checks in one expression. • SpEL can call arbitrary Spring beans, e.g. @PreAuthorize("@permissionService.canView(#id, authentication)"), enabling database-backed permission logic. • Method parameters are accessible by name using # prefixes when parameter names are compiled in or explicitly referenced with @P. • @PostAuthorize evaluates after the method runs, letting you check properties of the returned object before releasing it to the caller. • This flexibility comes at some cost to readability and testability, so expressions should stay reasonably simple or be delegated to a helper bean.
Example: An expense-approval method uses @PreAuthorize("hasRole('MANAGER') and #expense.amount <= 5000") so managers can only approve expenses under a certain threshold without a separate hardcoded rule per amount tier.
Code Example:
@PreAuthorize("hasRole('MANAGER') and #expense.amount <= 5000")
public void approveExpense(Expense expense) {
// approval logic
}Interview Tip: A concise interview answer is:
"SpEL inside @PreAuthorize or @PostAuthorize lets me write expressions that go beyond static roles—checking method arguments, calling custom permission beans, or inspecting the returned object. That gives fine-grained, context-aware access control tailored to the specific business rule rather than a blunt role check."