Web 应用程序使用 Spring WebMVC 和 Spring Security。问题出现了为什么 @PreAuthorize 注释如果挂在控制器类中的嵌套方法上不起作用:
@GetMapping(value= "/method")
public String exampleForMethodPreAuthorize() {
if(methodController()){
return "forMethodPreAuthorize";
}
else return null;
}
@PreAuthorize("hasRole('ADMIN')")
public final boolean methodController(){
return true;
}
上面的代码不起作用,即 该方法适用于任何用户,即使是没有管理员访问权限的用户。虽然,如果将此注释放在控制器方法本身上:
@PreAuthorize("hasRole('ADMIN')")
@GetMapping(value= "/method")
public String exampleForMethodPreAuthorize() {
return "forMethodPreAuthorize";
}
那么在这种情况下一切正常。自然地,servlet 上下文配置文件使用组件扫描和
<security:global-method-security pre-post-annotations="enabled"/>
提前感谢您的回复。
也许,我会扩展我的答案的两个版本,因为也许不是在这种特殊情况下,但必须考虑到这种行为的所有可能原因。
首先,Spring 将控制器 bean 包装在一个代理对象中,该对象拦截所有方法调用并检查权限是否与注解中的表达式匹配
@PreAuthorize。但是代理对象不能拦截目标对象内部的调用,只能拦截来自外部的调用。在使用许多注解时会遇到这种情况,而不仅仅是 Spring Security 注解。其次,在使用 Spring Security 的应用程序中,在到达调度程序 servlet之前和到达控制器之后,请求会通过一系列servlet 过滤器。
特别是通过FilterSecurityInterceptor,它只检查安全表达式的真实性,如果表达式为假,甚至在控制器接收控制之前就丢弃请求。
所以说实话,我很惊讶 Spring Security 在调用方法时会进行一次检查。
谢尔盖,你的第一个答案给了我一个想法,感谢我找到了我的问题的答案。实际上,控制器 bean 是代理的,显然正因为如此,内部方法调用不会检查 @PreAuthorize 注释。在使用@Component 注释的单独类中需要创建一个方法,该方法旨在从控制器方法调用,并使用@Autowired 将此类的bean 注入控制器类。事实是,使用@PreAuthorize 注释的机制本身是基于为相应类的bean 创建代理并检查此代理以查找方法调用是否存在此注释。因此,带有@PreAuthorize 注解的方法必须在bean 类中。或多或少是这样的: