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

相关推荐
2401_8734794038 分钟前
IP属地为什么有时显示外省?用IP查询工具核查动态分配、运营商出口与GeoIP库
python·tcp/ip·ip
wdfk_prog1 小时前
ros教程02:创建 catkin Workspace、Package 与第一个 ROS1 C++ Node
运维·缓存·docker·容器·ros
海宇AI1 小时前
零信任架构实战:基于海宇柠檬查出险-登记证构建自动化车抵贷核保网关
java·人工智能·架构·自动化
可爱系程序猿2 小时前
WSD 打印机时好时坏:从发现服务、地址变化到 Standard TCP/IP 端口的迁移记录
网络·网络协议·tcp/ip·程序人生·电脑
Bs_MoneyMagnet2 小时前
基于springboot+vue的心理咨询预约与随访平台的设计与实现 源码+文档
vue.js·spring boot·后端·spring·毕业设计·旅游·计算机毕业设计
cfm_29142 小时前
单例模式详解
java
我叫张土豆3 小时前
本体论、DDD、SDD、TDD:AI 编程时代的四层认知栈
java·人工智能
白远山3 小时前
家政服务家政社区派单实战:调度系统架构设计与实现指南
java·开发语言·小程序·架构·需求分析
海南java第二人3 小时前
从诞生到回收:JVM对象生命周期与垃圾回收全链路解析
java
SL_staff3 小时前
JVS-Logic:从页面配置工具到企业级业务逻辑中枢的技术演进
java·算法·全栈