2. 鉴权与拦截链路概述
在多租户 SaaS 架构中,每一次请求从进入网关到抵达业务逻辑,必须经过严格的鉴权与拦截链路。本章厘清两个核心概念(Authentication vs Authorization)、两种拦截机制(Interceptor vs Filter),并给出完整的请求链路全景图。
2.1 鉴权(Authentication)与授权(Authorization)的区别
鉴权与授权是安全体系中经常被混淆的两个环节,但职责完全不同:
| 维度 | 鉴权(Authentication) | 授权(Authorization) |
|---|---|---|
| 核心问题 | 你是谁? | 你能做什么? |
| 执行时机 | 请求链路最前端 | 鉴权通过之后 |
| 校验内容 | Token / Session / 证书 | 角色 / 权限 / 租户隔离策略 |
| 失败结果 | 401 Unauthorized | 403 Forbidden |
| 多租户场景 | 验证租户身份 + 用户身份 | 验证租户内资源访问范围 |
实践要点:鉴权失败直接阻断请求,不进入业务逻辑;授权失败通常返回明确错误码,便于前端展示权限不足提示。
2.2 拦截器(Interceptor)与过滤器(Filter)的作用
在 Java Web 体系中,Filter 和 Interceptor 是两种常见的请求拦截机制,它们在执行层级、作用范围和适用场景上存在明显差异:
| 对比项 | Filter(过滤器) | Interceptor(拦截器) |
|---|---|---|
| 规范层级 | Servlet 规范 | Spring MVC 框架 |
| 作用范围 | 所有 URL 请求(包括静态资源) | 仅 Controller 请求 |
| 执行顺序 | 先于 Interceptor 执行 | 在 Filter 之后、Controller 之前 |
| 典型用途 | 字符编码、跨域、XSS 过滤、Token 解析 | 权限校验、日志记录、租户上下文注入 |
| 是否可获取 Spring Bean | 需特殊配置 | 原生支持 |
推荐策略:Filter 负责全局性、低层级的预处理(如 Token 解析、租户识别);Interceptor 负责业务相关的鉴权与授权校验,便于复用 Spring 的依赖注入和 AOP 能力。
2.3 请求链路全景图
下图展示了一次完整的多租户 SaaS 请求从进入网关到返回响应的鉴权与拦截链路:
2.4 多租户上下文注入时机
在 Interceptor 链中,鉴权通过后需要立即将租户信息注入到当前请求上下文,供后续业务逻辑使用:
// 自定义 TenantInterceptor 示例
public class TenantInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 1. 从 Token 中解析租户 ID
String tenantId = extractTenantId(request);
// 2. 校验租户有效性(鉴权)
if (tenantId == null || !tenantService.isValid(tenantId)) {
response.sendError(HttpStatus.UNAUTHORIZED.value(), "无效租户");
return false;
}
// 3. 校验租户内权限(授权)
if (!permissionService.hasAccess(tenantId, request.getRequestURI())) {
response.sendError(HttpStatus.FORBIDDEN.value(), "权限不足");
return false;
}
// 4. 注入租户上下文
TenantContextHolder.set(tenantId);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
// 5. 请求结束后清理上下文,防止内存泄漏
TenantContextHolder.clear();
}
}
常见陷阱:租户上下文使用 ThreadLocal 存储时,务必在 afterCompletion 或 finally 块中清理,否则线程池复用会导致租户信息串号,引发严重的数据泄露事故。
2.5 链路拦截决策矩阵
在实际部署中,不同层级的拦截器负责不同粒度的校验,以下矩阵帮助团队快速决策:
| 拦截层级 | 校验内容 | 失败处理 | 配置方式 |
|---|---|---|---|
| 网关层 | Token 格式、签名、过期时间 | 直接返回 401,不进入内网 | 路由规则 + 全局过滤器 |
| Filter 链 | 请求编码、跨域头、基础安全过滤 | 抛出 ServletException | web.xml 或 @WebFilter |
| Interceptor 链 | 租户身份、资源权限、数据隔离 | 返回 401/403 JSON 响应 | WebMvcConfigurer 注册 |
| AOP 切面 | 方法级细粒度权限、数据脱敏 | 抛出业务异常 | @Aspect + 自定义注解 |
通过上述分层设计,多租户 SaaS 系统能够实现从网络层到业务层的全链路鉴权与拦截,既保证了安全性,又保持了各层职责的清晰分离。