Owner-only rules with a guard bean
Express "only the owner may edit this row" without copying the check into every controller method.
Open this lesson in the learning hubKey points
- Roles cannot answer "is this row yours". That needs the object, so the check belongs next to the data.
- Call a bean from SpEL:
@PreAuthorize("@postGuard.canEdit(#postId, authentication)")runs an ordinary query. - Prefer
@PreAuthorizewith an id to@PostAuthorizeon the result - a post-check does the work, then throws it away. - Filtering a list is a query concern. Add
where owner_id = ?instead of loading everything and filtering in Java. - A failed check throws
AccessDeniedException, so it lands on exactly the same 403 path as a URL rule. - Spring Security ACLs exist for per-row grants, but a small guard bean covers ownership with far less machinery.
Example
@Component("postGuard")
public class PostGuard {
private final PostRepository posts;
public boolean canEdit(Long postId, Authentication auth) {
boolean admin = auth.getAuthorities().stream()
.anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));
return admin || posts.findById(postId)
.map(p -> p.getAuthorEmail().equals(auth.getName()))
.orElse(false);
}
}
@Service
public class PostService {
@PreAuthorize("@postGuard.canEdit(#postId, authentication)")
public Post update(Long postId, PostForm form) { ... }
}
Ownership is a query, so let a small guard bean answer it from SpEL.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Spring Security course, and every lesson in it is listed on the Spring Security contents page.