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

相关推荐
萧瑟余晖9 小时前
Spring Data JDBC与R2DBC详解
java·后端·spring
杰克尼9 小时前
今日面试题总结
java·开发语言·人工智能·langchain
微订校园外卖平台9 小时前
县城多门店外卖履约系统怎么做:统一后台、共享骑手池与分店对账的架构清单
大数据·架构·外卖系统·本地生活·微订
4SAPI10 小时前
营销内容生成大模型 API 生产选型指南:4SAPI、硅基流动与 OpenRouter 的架构权衡
数据库·人工智能·架构·php
谢白羽10 小时前
从传统运维到 AI Infra: K8s 上调度 100 张 GPU踩坑笔记
运维·人工智能·缓存·kubernetes·vllm·sglang·vllm-omni
估值探索者10 小时前
【Python量化组合管理实战 02】钱该怎么分?等权、波动率倒数与动态评分三种配权实测
java·开发语言·python·接口·股票数据api接口
Wang's Blog10 小时前
Java 项目实战:交友项目环信云通信全解——体系集成、执行链路与 REST API 实战
java·spring·交友
god_cvz10 小时前
第三章:12、经验沉淀与自优化
java·ai
硅基手札10 小时前
操作系统设计思想系列 13 · NuttX 深度 — POSIX 飞控底座 + RTOS 群像
架构·操作系统·嵌入式开发·ecos·sel4·nuttx
小冯不疯10 小时前
查询旺店通货品策略实战教程:从源系统拉取到轻易云的端到端落地
java·大数据·数据库