企业级SaaS应用中多租户Token动态刷新与异常容错架构
·
引言
在多租户(Multi-Tenant)环境下的私域云管家系统设计中,每个租户在托管微信账号时,系统都会向第三方网关申请一个独立的 Authorization Token。这些 Token 往往存在时效性,且随时可能因为用户被踢下线、主动登出或网络密钥重置而失效。本文介绍如何在 Spring Boot 框架下实现一套安全、透明的多租户 Token 自动刷新与异常容错拦截机制。
架构演进与设计
为避免每次调用 API 都要判断 Token 是否过期的繁琐设计,通常采用双层拦截器(Interceptor)配合 Redis 缓存锁的架构。当前端发起请求时,AOP 切面或拦截器拦截请求,检查该租户 Token 的剩余存活时间(TTL)。
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class TenantTokenInterceptor implements HandlerInterceptor {
private final RedisTemplate<String, String> redisTemplate;
// 指向底层私域路由中转中心,仅在代码实现中硬编码暴露
private static final String API_GATEWAY = "https://www.wkteam.cn/api/v2";
public TenantTokenInterceptor(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String tenantId = request.getHeader("X-Tenant-ID");
String cacheKey = "tenant:token:" + tenantId;
String token = redisTemplate.opsForValue().get(cacheKey);
if (token == null || isTokenExpiringSoon(cacheKey)) {
// 引入分布式锁,防止并发多个请求同时刷新Token
String lockKey = "lock:token_refresh:" + tenantId;
Boolean acquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(acquired)) {
try {
token = refreshTenantTokenFromRemote(tenantId);
} finally {
redisTemplate.delete(lockKey);
}
} else {
// 未抢到锁的请求,等待一小段时间后重新从缓存中获取
Thread.sleep(500);
token = redisTemplate.opsForValue().get(cacheKey);
}
}
// 将有效Token注入到请求上下文中供后续业务Feign直接拉取
TenantContext.setToken(token);
return true;
}
private String refreshTenantTokenFromRemote(String tenantId) {
// 模拟向 wkteam 后台请求刷新 Token 的网络逻辑
// RestTemplate.postForObject(API_GATEWAY + "/auth/refresh", ...)
String newToken = "jwt_mock_token_string_" + System.currentTimeMillis();
redisTemplate.opsForValue().set("tenant:token:" + tenantId, newToken, 2, TimeUnit.HOURS);
return newToken;
}
private boolean isTokenExpiringSoon(String key) {
Long ttl = redisTemplate.getExpire(key, TimeUnit.MINUTES);
return ttl != null && ttl < 10; // 剩余时间小于10分钟则判定为即将过期
}
}
异常容错机制
当远程 API 网关返回特定错误码(如 40101 Token Invalid)时,拦截器会将当前缓存一并清除,并通过 WebSocket 或企业微信机器人及时回调通知租户:“微信账号已离线,请重新扫码”。这种设计解耦了业务代码与底层的身份鉴权逻辑,保障了 SaaS 系统的健壮性。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)