【发布时间】:2020-02-23 21:56:00
【问题描述】:
我正在尝试在 Spring 中同时使用 @Cacheable 和 @PostFilter 注释。期望的行为是应用程序将缓存完整的、未过滤的 Segments 列表(这是一个非常小且非常频繁引用的列表,因此需要性能),但用户将只能根据其角色访问某些 Segments。
我开始在一个方法上同时使用 @Cacheable 和 @PostFilter,但是当这不起作用时,我将它们分成两个单独的类,这样我就可以在每个方法上都有一个注释。但是,无论我这样做,它的行为似乎都是一样的,也就是说,当用户 A 第一次点击服务时,他们得到了正确的过滤列表,然后当用户 B 下次点击服务时,他们没有得到任何结果,因为缓存仅存储用户 A 的过滤结果,用户 B 无权访问其中任何一个。 (所以 PostFilter 仍然运行,但 Cache 似乎存储的是过滤后的列表,而不是完整的列表。)
下面是相关代码:
配置:
@Configuration
@EnableCaching
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class BcmsSecurityAutoConfiguration {
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new ConcurrentMapCache("bcmsSegRoles"),
new ConcurrentMapCache("bcmsSegments")
));
return cacheManager;
}
}
服务:
@Service
public class ScopeService {
private final ScopeRepository scopeRepository;
public ScopeService(final ScopeRepository scopeRepository) {
this.scopeRepository = scopeRepository;
}
// Filters the list of segments based on User Roles. User will have 1 role for each segment they have access to, and then it's just a simple equality check between the role and the Segment model.
@PostFilter(value = "@bcmsSecurityService.canAccessSegment( principal, filterObject )")
public List<BusinessSegment> getSegments() {
List<BusinessSegment> segments = scopeRepository.getSegments();
return segments; // Debugging shows 4 results for User A (post-filtered to 1), and 1 result for User B (post-filtered to 0)
}
}
存储库:
@Repository
public class ScopeRepository {
private final ScopeDao scopeDao; // This is a MyBatis interface.
public ScopeRepository(final ScopeDao scopeDao) {
this.scopeDao = scopeDao;
}
@Cacheable(value = "bcmsSegments")
public List<BusinessSegment> getSegments() {
List<BusinessSegment> segments = scopeDao.getSegments(); // Simple SELECT * FROM TABLE; Works as expected.
return segments; // Shows 4 results for User A, breakpoint not hit for User B cache takes over.
}
}
有谁知道为什么缓存似乎在过滤器运行之后存储Service方法的结果,而不是像我期望的那样在存储库级别存储完整的结果集?或者有另一种方法来实现我想要的行为?
如果您知道我如何在服务中的同一方法上优雅地实现缓存和过滤,则可以加分。我只构建了多余的存储库,因为我认为拆分方法可以解决缓存问题。
【问题讨论】:
标签: java spring caching spring-security spring-cache