多租户 GEO 优化系统源码架构:权限隔离与数据分离实现

1. 引言

多租户 GEO 优化系统在服务多个业务方时,需要同时解决两个核心问题:一是租户之间的权限隔离,确保每个租户只能访问自己的数据和功能;二是数据分离,避免租户数据互相污染。本文从源码架构角度,分析权限隔离与数据分离的具体实现方案。

2. 整体架构设计

系统采用分层架构,从上到下依次为接入层、服务层、数据访问层和存储层。权限隔离贯穿接入层和服务层,数据分离则主要在数据访问层和存储层落地。

text 复制代码
接入层(API Gateway / 租户上下文解析)
        ↓
服务层(业务服务 / 权限校验拦截器)
        ↓
数据访问层(多租户数据路由 / 数据源路由)
        ↓
存储层(共享库共享表 / 共享库独立表 / 独立库)

3. 权限隔离实现

3.1 租户上下文传递

租户标识通过请求头或 Token 解析后,写入线程上下文,供后续业务逻辑和拦截器使用。

java 复制代码
public class TenantContext {
    private static final ThreadLocal<String> TENANT_ID = new ThreadLocal<>();

    public static void setTenantId(String tenantId) {
        TENANT_ID.set(tenantId);
    }

    public static String getTenantId() {
        return TENANT_ID.get();
    }

    public static void clear() {
        TENANT_ID.remove();
    }
}

3.2 拦截器校验

在服务层入口统一校验租户权限,未携带合法租户标识的请求直接拒绝。

java 复制代码
public class TenantAuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String tenantId = request.getHeader("X-Tenant-Id");
        if (tenantId == null || tenantId.isEmpty()) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            return false;
        }
        TenantContext.setTenantId(tenantId);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        TenantContext.clear();
    }
}

3.3 接口级权限控制

对于敏感操作,在方法级别通过注解或配置进一步校验租户角色权限。

java 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TenantPermission {
    String[] roles() default {};
}

4. 数据分离实现

4.1 共享库共享表

所有租户共用同一张表,通过 tenant_id 字段区分数据归属。该方案成本最低,适合租户数据量小、隔离要求不高的场景。

sql 复制代码
CREATE TABLE geo_optimization_task (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    tenant_id VARCHAR(64) NOT NULL,
    task_name VARCHAR(128) NOT NULL,
    geo_config TEXT,
    status TINYINT DEFAULT 0,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    KEY idx_tenant_id (tenant_id)
);

4.2 数据访问层自动拼接租户条件

通过 MyBatis 拦截器或 JPA 过滤器,在 SQL 执行前自动追加 tenant_id 条件,避免业务代码重复编写。

java 复制代码
@Intercepts({
    @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class TenantSqlInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler handler = (StatementHandler) invocation.getTarget();
        BoundSql boundSql = handler.getBoundSql();
        String sql = boundSql.getSql();
        String tenantId = TenantContext.getTenantId();
        if (tenantId != null && !sql.contains("tenant_id")) {
            String newSql = injectTenantCondition(sql, tenantId);
            Field field = boundSql.getClass().getDeclaredField("sql");
            field.setAccessible(true);
            field.set(boundSql, newSql);
        }
        return invocation.proceed();
    }
}

4.3 共享库独立表

每个租户拥有独立的表,表名带租户前缀,数据物理隔离,但共享同一个数据库实例。适合租户数据量较大、需要独立备份的场景。

java 复制代码
public class TenantTableRouter {
    public String resolveTableName(String baseTableName, String tenantId) {
        return tenantId + "_" + baseTableName;
    }
}

4.4 独立数据库

每个租户独占一个数据库,隔离级别最高,适合对数据安全要求严格的租户。通过动态数据源路由实现。

java 复制代码
public class TenantDataSourceRouter extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return TenantContext.getTenantId();
    }
}

5. 缓存与文件存储隔离

Redis 缓存键统一加上租户前缀,文件存储路径按租户目录隔离,防止跨租户数据泄露。

java 复制代码
public class TenantCacheKeyBuilder {
    public static String build(String key) {
        return TenantContext.getTenantId() + ":" + key;
    }
}

6. 源码目录结构

text 复制代码
geo-optimization-system/
├── gateway/                 # 接入层,租户上下文解析
├── common/                  # 公共模块,租户上下文、拦截器
├── service/                 # 业务服务
│   ├── task/                # 优化任务服务
│   └── permission/          # 权限校验服务
├── dal/                     # 数据访问层
│   ├── interceptor/         # SQL 租户条件注入
│   └── router/              # 数据源与表路由
└── storage/                 # 存储层,缓存与文件隔离

7. 总结

多租户 GEO 优化系统的权限隔离与数据分离,核心在于租户上下文的统一传递、拦截器的集中校验,以及数据访问层的自动路由。实际项目中应根据租户规模、数据敏感度和成本要求,灵活选择共享表、独立表或独立库方案,并在缓存和文件存储层面同步落实隔离策略。

相关推荐
wear工程师32 分钟前
线程池队列满了会怎样?从拒绝策略看懂 ThreadPoolExecutor 的扩容顺序
java
AI行业应用研究33 分钟前
2026年主流报名工具测评报告:眨眼猫会务智能体报名小程序为何成为多场景首选?
java·开发语言·小程序
buligbulig33 分钟前
架构企业通往AI的桥梁
人工智能·架构
cxoptics35 分钟前
C-Lens在光模块(800G/1.6T)中的应用
java
liangbo738 分钟前
JVM规范第 1章:从一段历史到「JVM 并不认识 Java」
java·jvm
大锅盖139 分钟前
HarmonyOS 6.1.1 AI字幕新特性深度解析:从AICaptionComponent四大新增字段到K歌社交舞台黑霓虹紫深色架构全链路实战
人工智能·架构·harmonyos
TechExplorer3651 小时前
Tomcat 下载与安装
java·tomcat
程序员贺加贝1 小时前
列表导出不够用-SaaS-ERP-单据详情导出的-Provider-模板与文档型-Excel-设计
java·后端·设计模式·架构·excel
SimonKing1 小时前
写文档的最佳搭档:Typora+PicList+SM.MS
java·后端·程序员