在Spring Boot中,是否按请求缓存@PreAuthorize("@bean.checkAuthorization(#argument)")
个调用?
作为一个最小的示例,假设@Controller
具有以下REST端点:
@GetMapping("/api/test") public String testAuthorization() {
String argument;
String foo = service.foo(argument);
String bar = service.bar(argument); // same arguments
return bar + foo;
}
以及foo
中的bar
和service
方法的定义如下:
@PreAuthorize("@bean.checkAuthorization(#argument)")
public String foo(String argument) {
return "hello";
}
@PreAuthorize("@bean.checkAuthorization(#argument)")
public String bar(String argument) {
return "world";
}
用例。鉴于Bean.checkAuthorization(argument)
是一个运行成本很高的函数( eg 它会进行数据库调用),但它是无状态的( ie 对于给定参数的结果不会因多次调用而改变),每个请求仅需进行一次调用。因此,是否可以为整个请求缓存结果,但确保对每个请求都执行检查? (没有长期缓存)
答案 0 :(得分:1)
在实现这种方法时,您很容易受到缓存中毒攻击;也就是说,您将面临任何未经数据库调用授权的人所面临的威胁,而这种威胁就是您不希望他们获得的方式。
在确定是否应允许用户访问受保护资源而不是使该资源泄漏方面,对性能造成轻微影响是可取的。
更好的选择可能是调查造成数据库调用如此昂贵的原因,或者说服企业这是保护该资源所需要支付的费用。
答案 1 :(得分:0)
只需启用缓存:@EnableCaching
,然后将@Cacheable("checkauth")
放在checkAuthorization
方法的顶部即可。
编辑我意识到我的回答不符合要求,如下面的评论所述。肯定有一些特别的方法可以做到这一点,例如:Caching per request with Spring使用AOP
。
但是太复杂了!我想像一下,对于大多数具有保留策略@Cached(expire = 1, timeUnit = TimeUnit.MINUTES)
的现代Web应用程序,大多数请求都将花费一秒钟的时间,而预先优化是魔鬼。
但是对于这种标准问题,我发现这种方法真的是非标准的。相反,我建议您使用以下角色:FOO
和BAR
,这将使您可以简单地使用以下方法来注释方法:hasRole('FOO')
,hasRole('BAR')
。
@Service
public class MyUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByUsername(username);
if (checkAuthorizationFoo(user)) user.addRole("FOO");
if (checkAuthorizationBar(user)) user.addRole("BAR");
return new user;
}
}
@PreAuthorize("hasRole('FOO')")
public String foo(String argument) {
@PreAuthorize("hasRole('BAR')")
public String bar(String argument) {
请注意,尽管这并不是很懒,并且您的checkAuthorization
方法总是被调用,但这是这种方法的缺点。您可以花点时间使它变得懒惰,但是再次注意要进行多少优化。