java Spring Security 在类型级别的 @PreAuthorize 不能在方法级别被覆盖

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7634895/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 20:46:50  来源:igfitidea点击:

Spring Security's @PreAuthorize on type level can not be overridden on method level

javaspringspring-security

提问by chzbrgla

I'm trying to protect a Controller with the @PreAuthorizeannotation at type level and try to override that behavior by annotating some methods with a different @PreAuthorize. The Problem is however, that Spring is evaluating the method annotation first (grants access) and is then evaluating the class annotation (denies access).

我正在尝试使用@PreAuthorize类型级别的注释来保护控制器,并尝试通过使用不同的@PreAuthorize. 然而,问题是 Spring 首先评估方法注释(授予访问权限),然后评估类注释(拒绝访问)。

Is there any way to reverse that order? I couldn't figure it out yet.

有什么办法可以颠倒这个顺序吗?我还想不通。

Edit:

编辑:

On the method level, I want to grant access to non-registered Users only:

在方法级别,我只想授予非注册用户访问权限:

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

The standard for this Controller however, should be to allow fully authenticated users only:

但是,此控制器的标准应该是仅允许完全经过身份验证的用户:

@Controller
@RequestMapping(value = "/user")
@PreAuthorize("isFullyAuthenticated()")
public class UserController { [...] }

When debug-stepping through the app, I see that isAnonymous()is evaluated first and then isFullyAuthenticated()thus resulting in an grant of access right and immediately denying access again.

当调试单步调试应用程序时,我看到它isAnonymous()首先被评估,然后isFullyAuthenticated()导致授予访问权限并立即再次拒绝访问。

回答by chzbrgla

Thanks for all your replys. The answer however, was something totally different :)

感谢您的所有回复。然而,答案是完全不同的:)

I put this here in case anyone else has the same problems.

我把它放在这里以防其他人有同样的问题。

I registered a custom validator in an @InitBinderannotated method. This binding method is called AFTER the method call requested on the controller. And since this binding method was not annotated with @PreAuthorize, the request was denied.

我在带@InitBinder注释的方法中注册了一个自定义验证器。在控制器上请求的方法调用之后调用此绑定方法。并且由于此绑定方法未使用 注释@PreAuthorize,因此请求被拒绝。

The solution was to annotate the binding method like this:

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

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

And then, the method calls from my OP evaluated like expected.

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

回答by Ralph

The problem is not that you need to change the order of grant and deny. The problem is simple that that method level annotations overridethe class level annotations.

问题不在于您需要更改授予和拒绝的顺序。问题很简单,方法级别的注释覆盖了类级别的注释。

PrePostAnnotationSecurityMetadataSourceJava Doc:

PrePostAnnotationSecurityMetadataSourceJava文档:

Annotations may be specified on classes or methods, and method-specific annotations will take precedence.

可以在类或方法上指定注解,并且特定于方法的注解将优先。

The concrete implementation of this logic is done in the method findAnnotationof class PrePostAnnotationSecurityMetadataSource. (Unfortunately this method is private.)

这个逻辑的具体实现是在findAnnotation类的方法中完成的PrePostAnnotationSecurityMetadataSource。(不幸的是,此方法是私有的。)

So you can write your own MethodSecurityMetadataSource, if you have a look at the code of PrePostAnnotationSecurityMetadataSource, you will see how easy it is.

所以你可以自己写MethodSecurityMetadataSource,如果你看一下 的代码PrePostAnnotationSecurityMetadataSource,你会发现它是多么容易。

But one warning at the end: the end: difficult task is not rewriting the method, the difficult task is to "inject" the new MethodSecurityMetadataSourceinto the security system. I belive you can not do it with the spring security namespace configuration, so you need to replace spring security namespace by explicit bean declaration.

但最后一个警告:最后:难的不是重写方法,难的是将新的“注入”MethodSecurityMetadataSource到安全系统中。我相信你不能用 spring 安全命名空间配置来做到这一点,所以你需要用显式 bean 声明替换 spring 安全命名空间。