基于JPA、Hibernate、Spring在SQL映射表实现多租户安全管控
解决方案
完全可以通过Hibernate过滤器实现该管控,无需每次手动做查询校验,常用两种实现方式:
方式1:给多对多关联追加过滤器注解
你已经给User实体定义了全局account_id过滤器,只需要在Task的assignedUsers关联上追加过滤器配置即可:
public class Task { ... @ManyToMany(fetch= FetchType.LAZY) @JoinTable( name = "task_assignee", joinColumns = { @JoinColumn(name = "task_id") }, inverseJoinColumns = { @JoinColumn(name = "user_id") } ) @Filter(name = "account_id", condition = "account_id = :account_id") List<User> assignedUsers; }
配置生效后,只要你提前在会话中启用了account_id过滤器,往关联列表中添加不属于当前租户的User实例时,Hibernate执行关联插入前会自动校验实体是否符合过滤条件,不符合会直接抛出异常,不会写入task_assignee表。
方式2:给中间表加双向校验(更严格)
如果要彻底避免跨租户关联,还可以直接给中间表配置过滤器,校验关联的task和user都属于当前租户:
@ManyToMany(fetch= FetchType.LAZY) @JoinTable( name = "task_assignee", joinColumns = { @JoinColumn(name = "task_id") }, inverseJoinColumns = { @JoinColumn(name = "user_id") } ) @Filter( name = "account_id", condition = """ EXISTS (SELECT 1 FROM task t WHERE t.id = task_id AND t.account_id = :account_id) AND EXISTS (SELECT 1 FROM user u WHERE u.id = user_id AND u.account_id = :account_id) """ ) List<User> assignedUsers;
注意点
- 所有写入操作执行前必须确保会话的
account_id过滤器已启用并设置了正确参数,过滤器未生效时校验规则会失效 - 如果你要添加的
User是游离态实例(非当前会话加载的持久态对象),Hibernate不会自动触发校验,这种情况需要先通过find()/getReference()方法加载持久态实例再加入关联列表,过滤器才会生效
内容的提问来源于stack exchange,提问作者Half_Duplex
相关产品推荐
相关产品推荐

