Can We use Spring Security's @PreAuthorize
, @PostAuthorize
, @PreFilter
or @PostFilter
on JPA's @Entity
methods?
Only recommendations/answers I found are 6+ year old threads and usually say "Use service layer" and sometimes "controllers can also have security annotations, but service layer is more straightforward".
Noone every talks about using security annotations on @Entity
.
To explain simple use case:
Say we have 3 Spring's JpaRepositories
for Person
and Group
and Party
:
@Entity
class Person {
...
@ManyToOne
Group group;
@ManyToOne
Party party;
}
@Entity
class Group {
...
@OneToMany
List<Person> people;
@ManyToOne
Party party;
}
@Entity
class Party {
...
@OneToMany
List<Person> people;
@OneToMany
List<Group> groups;
}
So basically - one person can belong to one group and at the same time to one party. One group can also belong to one Party and has many people. And one party consists of many groups and many separate people (that might or might not be in groups).
Lots of code, like mappedBy
, ids and getters/setters/adders/removers were omitted for brevity.
If I could secure Entity methods, i can do:
@Entity
class Party {
...
@PreAuthorize("hasRole('ROLE_ADMIN')")
List<People> getPeople() { return this.people; }
}
@Service
class PartyService {
@Autowired
PartyRepository repo;
List<People> getPeople(Long partyId) {
return repo.getById(partyId).getPeople(); // Should either return people or throw access exception.
}
}
@Service
class GroupService {
@Autowired
GroupRepository repo;
List<People> getPeopleInMyParty(Long groupId) {
return repo.getById(groupId).getParty().getPeople(); // Should either return people or throw access exception.
}
}
If I cant secure Entity method, it leaves me with going through services, like:
@Entity
class Party {
...
// Not secured here
List<People> getPeople() { return this.people; }
}
@Service
class PartyService {
@Autowired
PartyRepository repo;
@PreAuthorize("hasRole('ROLE_ADMIN')")
List<People> getPeople(Long partyId) {
return repo.getById(partyId).getPeople(); // Should either return people or throw access exception.
}
}
@Service
class GroupService {
@Autowired
GroupRepository repo;
@Autowired
PartyService partyService;
List<People> getPeopleInMyParty(Long groupId) {
return partyService.getPeople(repo.getById(groupId).getParty().getId()); // Should either return people or throw access exception.
}
}
This poses complications in my much more sophisticated JPA data model (and its fetching service) as We get more and more @Service and @Repository injections all over the place and code becomes confusing to maintain. Look at difference between GroupService
between 2 examples - if You scale that up, You'll get TONS of IDs and injections to all related services, instead of just doing @Entity
method calls.
So can I do it at @Entity
level and how to enable it?