Reputation: 4472
In order to create row-level authorization, I want to use @Filter
and @FilterDef
hibernate annotations in combination with JpaRepository<T, ID>
interface of spring-data. Suppose that, we have a following entities:
@Entity
public class User {
@Id
private Long id;
private String name;
@ManyToOne
private Pharmacy pharmacy;
}
@Entity
public class Pharmacy {
@Id
private Long id;
private String name;
}
I want to create authorization based on whom send requests to server. For this purpose, I've added @Filter
and @FilterDef
annotations top of the Pharmacy
entity. So, the pharmacy should be like below:
@Entity
@FilterDef(name = "pharmacyFilter", parameters = {@ParamDef(name = "userId", type = "long")})
@Filters({
@Filter(name = "pharmacyFilter", condition = "id in (select user.pharmacy_id from user where user.id = :userId)")
})
public class Pharmacy {
//...
}
The repository that I've created to access database is one that seen below:
@Repository
public interface PharmacyRepository extends JpaRepository<Pharmacy, Long> {
}
When I make pharmacyFilter
enabled, everything works fine and the filter applied on all queries. You can see the query generated for repository.findAll()
as follows:
select pharmacy0_.id as id1_0_, pharmacy0_.name as name2_0_ from pharmacy pharmacy0_ where pharmacy0_.id in (select user.pharmacy_id from user where user.id = ?)
But, the problem occurred when I want to try using repository.findById(ID id)
. When I use the mentioned method, the filter won't applied to the final query and we will see the following sql in the terminal:
select pharmacy0_.id as id1_0_0_, pharmacy0_.name as name2_0_0_ from pharmacy pharmacy0_ where pharmacy0_.id=?
I guessed the problem is due to using id multiple times. One in findById
and another in filter condition. But when I tried to create query using session
object, this problem didn't occurred and output is desirable:
select pharmacy0_.id as id1_0_, pharmacy0_.name as name2_0_ from pharmacy pharmacy0_ where pharmacy0_.id in (select user.pharmacy_id from user where user.id = ?) and pharmacy0_.id=2
The problem is resolved using the following approach, but what happens when we use the JpaRepository#findById default implementation?
@Query(value = "from Pharmacy where id = :id")
Optional<Pharmacy> findById(Long id);
Thanks in advance.
Upvotes: 8
Views: 5085
Reputation: 1
As others mentioned there are a few solutions,
Using @Query
@Query(value = "from Pharmacy where id = :id")
Optional<Pharmacy> findById(Long id);
The one that probably takes the least to implement is
Optional<Pharmacy> findOneById(Long pharmacyId);
since findOneById is not part of Jpa it doesn't call EntityManager.find and filters are correctly applied.
Upvotes: 0
Reputation: 41
Hi there try this will apply any filter by bypass default springboot findById
@Repository
public interface PharmacyRepository extends JpaRepository<Pharmacy, Long> {
@Override
default Optional<Pharmacy> findById(Long id) {
return findOne(Example.of(Pharmacy.builder().id(id).build()));
// or with predicate
}
}
Upvotes: 0
Reputation: 13041
As it is stated in the hibernate documentation:
Filters apply to entity queries, but not to direct fetching.
But under the hood repository.findById(ID id)
method calls EntityManager.find
.
So, this is expected behaviour.
Upvotes: 8