微服务多租户越权防护核心是存储层结构化隔离,而非仅加权限校验:强制绑定租户上下文至数据库、对象存储、缓存等所有存储操作,并按风险等级实施物理/逻辑分离,构建网关—业务—存储三级防线。
在微服务生产环境中,利用存储隔离策略防范多租户越权,核心不是“加一层权限校验”,而是让越权请求在抵达业务逻辑前就失去可行性——即通过存储层的结构设计,使非法访问天然无法命中有效数据。
存储层必须绑定租户上下文
所有存储操作(读、写、删、查)都需强制注入租户标识,且该标识不能由前端传入或参数拼接,而应从认证后的上下文(如 JWT payload 或网关注入 header)中提取并透传至数据访问层。例如:
- 数据库查询统一拦截:使用 MyBatis-Plus 多租户插件或自定义 DataSource 路由,自动在 WHERE 条件中追加 tenant_id = ?,且禁止显式绕过(如 SQL 中写死 1=1)
- 对象存储路径强制前缀化:文件上传路径格式为 /{tenant_id}/bucket/{uuid}.pdf,而非 /uploads/{uuid}.pdf;下载时 URL 解析也必须校验前缀匹配,不依赖客户端传参
- 缓存 key 命名强约束:Redis key 必须包含 tenant_id,如 cache:order:20240527:tenant_88a3:12345,避免跨租户 key 冲突或误击
按租户粒度实施物理或逻辑存储分离
隔离强度需匹配业务风险等级,不能只靠代码层“租户过滤”:
- 高敏感场景(如金融、医疗):采用独立数据库或独立 Schema。每个租户拥有专属数据库实例或 MySQL Schema,网络与连接池完全隔离,从根本上杜绝 SQL 注入或配置错误导致的数据串访
- 中等规模 SaaS(数百租户):共享数据库 + 独立 Schema 是较优平衡点。Schema 名可映射租户唯一 ID(如 tenant_prod_abc123),配合动态数据源路由,既支持租户级 DDL 自定义,又避免单库性能瓶颈
- 海量轻量租户(如工具类应用):共享 Schema 模式下,必须启用存储层二次校验——例如,文件下载接口收到 /file/abc123 路径后,先查元数据表确认该文件所属 tenant_id,再比对当前请求上下文,不一致则 403,不直接拼 SQL 查询
越权防护必须贯穿访问链路全程
单点校验易被绕过,需构建“网关拦截 + 业务校验 + 存储层兜底”三级防线:
- API 网关层:基于 JWT 中的 tenant_id 和 scope 字段做初步鉴权,并剥离可疑参数(如 ?tenant_id=other)
- 业务服务层:在 Controller 或 Service 入口处,校验请求资源 ID(如订单号、文件 UUID)是否归属当前租户,可通过关联查询或缓存预检
- 存储驱动层:对象存储 SDK 或 DB 客户端封装租户感知能力。例如,调用 putObject() 时自动补全 bucket 和 prefix;执行 SELECT 时自动绑定 tenant_id 参数,不允许裸表操作
文件类资源要特别强化路径与权限联动
URL 越权是高频风险点,仅靠权限字段控制远远不够:
- 禁用直接暴露真实存储路径:所有文件访问走统一代理接口(如 /api/v1/files/{id}),不提供原始 OSS/MinIO 签名 URL 给前端
- 文件元数据必须持久化租户归属:每条 file_record 表记录含 tenant_id、owner_user_id、resource_type,并建立联合索引(tenant_id, id)提升校验效率
- 支持细粒度继承式权限:如 Puter 的 fs:/shared:read 模型,目录级授权自动覆盖子项,避免因遗漏子文件授权导致越权下载











