Spring Security的@PreAuthorize在类型级别上无法在方法级别上被覆盖。

18

我正在尝试使用@PreAuthorize注解来保护一个控制器,并尝试通过对某些方法使用不同的@PreAuthorize来覆盖该行为。然而问题在于,Spring首先评估方法注解(授权访问),然后再评估类注解(拒绝访问),导致无法实现我的目标。

是否有办法改变这个顺序呢?我还没有想出来。

编辑:

在方法级别上,我想允许未注册用户访问:

@PreAuthorize("isAnonymous()")
@RequestMapping(value = "/create", method = RequestMethod.GET)
public String renderCreateEntity(ModelMap model) {
    return userService.renderCreateEntity(model);
}

然而,该控制器的标准应该允许完全经过身份验证的用户:

@Controller
@RequestMapping(value = "/user")
@PreAuthorize("isFullyAuthenticated()")
public class UserController { [...] }
当通过调试应用程序时,我发现首先对 isAnonymous() 进行评估,然后是 isFullyAuthenticated(),从而导致授予访问权限,接着立即再次拒绝访问。

你使用的Spring Security版本是哪个? - beny23
一切Spring都是3.0.5.RELEASE。 - chzbrgla
2个回答

16

谢谢大家的回复。 然而,答案完全不同 :)

我把这个放在这里,以防其他人遇到相同的问题。

我在一个带有@InitBinder注释的方法中注册了自定义验证器。 这个绑定方法在控制器上请求的方法调用之后才被调用。 由于这个绑定方法没有用@PreAuthorize注释,所以请求被拒绝了。

解决方案是像这样注释绑定方法:

@InitBinder
@PreAuthorize("permitAll")
public void initBinder(WebDataBinder binder) {
    binder.setValidator(validator);
}

然后,我的 OP 中的方法调用按预期进行了评估。


5
问题不在于需要更改授权和拒绝的顺序,问题在于方法级别的注解覆盖了类级别的注解。 PrePostAnnotationSecurityMetadataSource Java文档:

注释可以在类或方法上指定,具有方法特定的注释优先。

此逻辑的具体实现在类PrePostAnnotationSecurityMetadataSourcefindAnnotation方法中完成。(不幸的是,此方法是私有的。)
因此,如果您查看PrePostAnnotationSecurityMetadataSource的代码,就可以编写自己的MethodSecurityMetadataSource,并使您的方法覆盖类级别的注解。
最后,有一个警告:难点不在于重写方法,而在于将新的MethodSecurityMetadataSource“注入”到安全系统中。我相信您无法通过Spring安全性命名空间配置来完成它,因此您需要使用显式bean声明来替换Spring安全性命名空间。

我实际上希望方法级别的注解可以覆盖类级别的注解。但是方法级别的注解先被评估,类级别的注解后被评估,因此类级别的注解实际上覆盖了方法的注解。我会在我的问题中编辑一些示例。 - chzbrgla
1
从我的测试来看,这个说法已经不再正确了。如果你在类级别和方法级别都有安全注解(@Secured或@PreAuthorized),它们都会被执行。如果方法级别的注解更加严格,那就没问题。如果它不够严格,那么它就不起作用。我最终将不够严格的方法拆分到另一个控制器中。 - Guy Schalnat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接