繁体   English   中英

使用Spring和Hibernate和Tomcat在无状态环境中实现多租户

[英]Implement multi tenancy in a stateless environment using Spring and Hibernate and Tomcat

我试图了解我们如何为涉及多租户的SaaS产品构建RESTful API。 该技术栈是使用Spring和Hibernate并将Java部署到Tomcat的Java。

我的主要问题是如何在REST调用中维护tenant_id,以便应用程序在执行CRUD时使用正确的数据库连接。 看到Tomcat使用线程池并重用线程,我们不应该使用ThreadLocal。

我已经阅读到slf4j通过MDC实现来支持此功能以进行日志记录。 一个servelet过滤器确实会预先维护tenant_id并在过滤器退出时将其清除。 因此,记录器在消息中使用正确的tenant_id。

同时使用ThreadLocal违反了无状态原理,因为它隐式地添加了一个状态。

此外,创建某种类型的ContextSession对象(包含tenant_id)并将其传递的想法似乎无法解决我的问题。 由于此对象将向下传递到DAL和DAO的各层以加载对象。 我想避免在此ContextSession类上的这种高度耦合,以及必须将其包括在许多方法签名中。

如何在无状态环境中实施多租户?

当用户登录到您的应用程序时,他们将以某种方式与租户相关联。 因此,应该可以从spring SecurityContext中访问租户信息。

例如,如果我有一个包含2个租户的应用程序; 租户A和租户B。 登录时,用户需要以某种方式指示他们属于哪个租户。 这可以通过多种方式来完成,例如使用不同的主机名(例如tenantA.myapp.com,tenantB.myapp.com)或url参数,或者以登录形式输入租户信息。 在对用户进行身份验证时,您需要使用与特定租户关联的身份验证领域。 作为身份验证的一部分,应该将spring SecurityContext设置为包含一些信息,这些信息使您可以在用户随后的服务调用中确定用户属于哪个租户。 应该可以从应用程序的不同服务层访问SecurityContext,而无需显式编写任何程序以实现此目的。

有多种方法可以将当前的HttpSession与特定的租户相关联。

  1. 在URL上提供某种类型的client_id参数,该参数用于通过集中式公共客户端数据库反向查找指定的后端tenant

  2. 将经过身份验证的用户与特定tenant关联。 当用户通过集中式用户数据库进行身份验证时,将根据用户帐户查找租户。

tenant_id如何传递给较低的应用程序层确实是一个问题。

我的第一个选择是使用ThreadLocal 如果您已经在使用Spring Security,那么您已经在使用ThreadLocal变量,甚至可能不知道它。

使用ThreadLocal变量不会破坏应用程序的无状态设计。 您只有一段代码期望变量包含必须使用的特定值。 这只是一种在整个应用程序层之间传递状态而不实际将状态作为方法签名上的参数显式传递的奇特方法。

显然,其他两个选项是使用某些Context对象或仅将值直接传递到下游。

在Web应用程序中,我通常会通过一些拦截器或过滤器来执行此操作,该拦截器或过滤器将按请求查找请求参数client_id并获取关联的tenantId并将其设置在特殊的ThreadLocal变量中。

一旦调用chain.doFilter( request, response ); 返回或引发异常,您只需清除ThreadLocal变量即可。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM