Skip to content

多租户开发 ​

为业务表接入租户数据隔离只需一个注解或一次继承,下面两种方式任选其一即可。

方式一:注解实现多租户 ​

在修饰 @Erupt 注解的类中增加 @EruptTenant 注解,使用 tenantField 属性指定租户字段名(默认为 tenantId),适合想用非 tenantId 名称作为租户字段的场景。租户会话下,租户字段值会自动填充与应用。

java
@Erupt
@Table(name = "t_tenant_test")
@EruptTenant(tenantField = "tenantId")
public class TenantDemo extends BaseModel {

    @Column(length = 50)
    private String tenantId;

    @EruptField(
        views = @View(title = "姓名"),
        edit = @Edit(title = "姓名", notNull = true)
    )
    private String name;

}

方式二:继承实现多租户 ​

@EruptTenant 注解带有 @Inherited 元注解 —— 只要父类中存在 @EruptTenant,子类会自动继承租户字段与注解处理逻辑:

java
@Entity
@Table(
        name = "t_tenant_demo",
        indexes = @Index(columnList = EruptTenant.TENANT_FIELD) // indexes 表示为租户字段创建索引,建议保留
)
@Erupt(name = "租户数据管理")
public class StudentTenant extends TenantMetaModel {

    @EruptField(
            views = @View(title = "姓名"),
            edit = @Edit(title = "姓名", notNull = true)
    )
    private String name;

    @EruptField(
            views = @View(title = "性别"),
            edit = @Edit(title = "性别",
                    boolType = @BoolType(trueText = "男", falseText = "女"))
    )
    private Boolean sex;

}

上面继承的 TenantMetaModel 可自动维护租户信息与审计信息,更多可继承父类如下:

类名功能
TenantBaseModel自动管理租户 ID 字段与主键自增 ID
TenantMetaModel继承自 TenantBaseModel,自动管理创建与更新信息
TenantMetaModelCreateVo继承自 TenantMetaModel,显示创建人与创建时间
TenantMetaModelUpdateVo继承自 TenantMetaModel,显示更新人与更新时间

数据隔离机制 ​

@EruptTenant 内部通过 @PreDataProxy(EruptTenantDataProxy.class) 在数据操作的各个环节自动完成租户隔离:

操作隔离行为
新增自动将当前会话的租户 ID 写入租户字段,无需手动赋值
查询自动追加 租户字段 = 当前租户 ID 查询条件;非租户会话(超管端)下条件为 租户字段 is null
修改 / 删除校验数据的租户字段与当前租户一致,不一致直接抛出 Cross-tenant permissions 异常,杜绝越权操作

也就是说,业务代码中完全不需要出现任何租户过滤逻辑,注解即隔离。

获取 TenantId ​

业务代码中如需感知当前租户,注入 EruptTenantContext 即可:

java
@Service
public class TextService {

    // 注入租户上下文对象
    @Resource
    private EruptTenantContext eruptTenantContext;

    public void test() {
        // 获取当前请求租户tenantId
        String tenantId = eruptTenantContext.getTenantId();
    }

}

实现原理

租户 ID 保存在服务端登录会话中,token 本身是不透明随机串(租户 token 以 t_ 前缀区分)。安全拦截器在校验会话后把租户 ID 写入 MetaContext 的 MetaUser,EruptTenantContext.getTenantId() 从中读取,并同步写入 MetaContext 变量 tenantId,erupt-report、erupt-cube 中可直接使用 ${tenantId} 参数;非租户会话(如超管端登录)返回 null。erupt-cloud-server 转发请求时会把 MetaUser 一并传给节点,因此 erupt-cloud-node 只需依赖 erupt-tenant-core,无需 upms 或会话存储即可完成租户隔离。

同时 TenantInterceptor 拦截器会将 tenantId 注册为 erupt-api 请求的上下文变量,动态 SQL 等场景可直接引用。

结合 erupt-bi ​

INFO

1.12.17 及以上版本支持

erupt-bi 支持动态 SQL 能力,任意出现 SQL 的地方都可以使用 :tenantId 或 ${tenantId} 获取当前租户的 ID,达到租户内 BI 数据隔离的能力,同样的报表在不同的租户展示不同的分析结果。

贡献者

The avatar of contributor named as YuePeng YuePeng
The avatar of contributor named as Claude Fable 5.1 Claude Fable 5.1

页面历史

Released under the Apache-2.0 License.