缓存安全机制:基于Token与权限验证的访问控制对比
最近在做后端服务缓存一致性优化时,踩了一个坑,分享给大家。我们团队在实现缓存访问控制时,选择了两种不同的方案:基于Token的认证和基于权限的访问控制。
问题背景
我们的系统需要对不同用户访问缓存数据进行严格控制。在项目初期,我们采用了传统的Token机制,通过JWT Token验证用户身份,然后根据用户角色决定是否允许访问特定缓存数据。
方案对比
方案一:Token + 权限验证
@GetMapping("/user/{id}")
public ResponseEntity<User> getUser(@PathVariable String id) {
String token = request.getHeader("Authorization");
if (!validateToken(token)) {
return ResponseEntity.status(401).build();
}
// 验证用户权限
if (!hasPermission(token, "user:read")) {
return ResponseEntity.status(403).build();
}
User user = cacheService.get("user:" + id);
return ResponseEntity.ok(user);
}
这个方案看似合理,但实际运行中出现了缓存穿透问题。当用户权限发生变化时,旧Token仍然可以访问被禁止的数据。
方案二:缓存预授权机制
@GetMapping("/user/{id}")
public ResponseEntity<User> getUser(@PathVariable String id) {
// 先验证Token
String userId = validateTokenAndGetUserId();
// 缓存权限检查
if (!isUserAuthorized(userId, id)) {
return ResponseEntity.status(403).build();
}
// 获取缓存数据
User user = cacheService.get("user:" + id);
return ResponseEntity.ok(user);
}
实际踩坑经历
在测试环境中,我们发现方案一的Token过期后,用户仍然能访问数据。问题出在缓存更新策略上:当权限变更时,没有及时清除相关的缓存,导致了缓存不一致。
复现步骤:
- 用户A拥有权限访问用户B数据
- 缓存中存储了用户A的权限信息
- 管理员撤销用户A的权限
- 但缓存未更新,用户A仍能访问用户B数据
解决方案: 在权限变更时,我们添加了缓存清理逻辑:
@Async
public void clearUserCache(String userId) {
// 清除相关缓存
cacheService.evict("user:" + userId);
cacheService.evict("permissions:" + userId);
}
最终选择方案二,并结合异步缓存清理,确保了缓存一致性。
总结
在实际开发中,缓存安全机制不能只依赖Token验证,还需要考虑权限变更后的缓存更新策略。特别是当权限控制涉及大量数据时,必须建立完善的缓存失效机制。

讨论