使用Spring Boot和Spring Data全局启用Hibernate过滤器

13

我正在尝试使用Spring Boot和Spring Data实现基于鉴别器的多租户。

我创建了一个抽象类来表示多租户实体,类似于以下内容:

@MappedSuperclass
@FilterDefs({@FilterDef(name = "multi-tenant", parameters = {@ParamDef(name = "tenant", type = "string")})})
@Filter(name = "multi-tenant", condition = "tenant = :tenant")
public abstract class MultiTenantEntity extends GenericEntity {
    @Transient
    private transient String savedTenant;

    @PostLoad
    private void onLoad() throws Exception {
        this.savedTenant = this.tenant;
        onEntityModification();
    }

    @PrePersist
    private void onPersist() {
        if (getId() == null || getId().equals(0l)) {
            tenant = SecurityUtil.getCurrentTenant();
        }
    }

    @PreUpdate
    @PreRemove
    private void onEntityModification() throws Exception {
        String currentTenant = SecurityUtil.getCurrentTenant();

        if (!currentTenant.equals(tenant) || !savedTenant.equals(tenant)) {
            throw new Exception();
        }
    }

    @NotNull
    private String tenant;

    public String getTenant() {
        return tenant;
    }
}

如何在全局启用 多租户 hibernate 过滤器?


如果有更好的想法来使用Spring-Data实现基于列的多租户,即使不使用Hibernate过滤器,我也很乐意听取建议。 - Daniel Gomes
你是否曾经找到一个好的解决方案,希望它仍然是最新的? - pvgoddijn
很遗憾,不行。 - Daniel Gomes
现在,一年过去了,你最终找到解决方案了吗?我处于同样的情况,但无法使其工作... - Moltes
1
使用AOP https://dev59.com/o1wY5IYBdhLWcg3wyaPV#32230857 - Lukasz Frankowski
2个回答

1
使用Hibernate过滤器可以轻松实现多租户,甚至可以在我们的应用程序中实现行级ACL。您可以使用AOP和不同的可配置过滤器来替代判别器。在调用请求方法之前,根据访问用户应用过滤器,启用Hibernate会话过滤器并执行请求,在成功处理请求后禁用过滤器。就是这样。使用这种方式,您可以为当前用户要操作的任何数量的实体添加任意数量的过滤器,并使用此方法进行完美的资源(实体和CRUD)管理。

https://dev59.com/333aa4cB1Zd3GeqPaj89#45935879 - Hakuna Matata

-1
您可以使用Spring的HandlerInterceptor以及Spring的Open Session in View来实现此目的:

确保启用了Open Session in View

application.yml

spring:
  jpa:
    open-in-view: true

添加一个HandlerInterceptor

@Component
public class HibernateInterceptor implements HandlerInterceptor {

    @Autowired
    private EntityManager entityManager;

    @Override
    @Transactional
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Session session = entityManager.unwrap(Session.class);
        session.enableFilter("multi-tenant")
               .setParameter("tenant", "my-tenant-value");

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        Session session = entityManager.unwrap(Session.class);
        session.disableFilter("multi-tenant");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // This method is called after the response has been sent to the client
    }
}

配置HandlerInterceptor

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private HibernateInterceptor hibernateInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(hibernateInterceptor).order(Ordered.LOWEST_PRECEDENCE);
    }
}

关键是要确保在 Spring 的 OpenEntityManagerInViewInterceptor 运行之后运行 HandlerInterceptor - 可以通过将顺序设置为 Ordered.LOWEST_PRECEDENCE 来实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接