如何使@PreAuthorize 的优先级高于@Valid 或@Validated

How to make @PreAuthorize having higher precedence than @Valid or @Validated

我正在使用 spring 引导,并且我已通过

在 WebSecurityConfigurerAdapter 中启用了全局方法安全性
@EnableGlobalMethodSecurity(prePostEnabled = true, order = Ordered.HIGHEST_PRECEDENCE) 

下面是我的控制器代码

@PreAuthorize("hasAnyRole('admin') or principal.id == id")
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public User updateUser(@PathVariable("id") String id,  @Valid @RequestBody   UserDto userDto) 
{ ....}

但是,当非管理员用户尝试执行 PUT 请求时,JSR303 验证程序将在 @PreAuthorize 之前启动。 例如,非管理员用户最终得到的是 "first name is required" 而不是 "access denied"。但是在用户提供名字变量通过验证器后,返回拒绝访问。

有谁知道如何在@Valid 或@Validated 之前强制检查@PreAuthorize?

而且我必须使用这种方法级授权而不是基于 url 的授权才能执行一些复杂的规则检查。

对于相同的场景,我发现了通过 spring 过滤器实现安全性的建议。
这是类似的 post : How to check security acess (@Secured or @PreAuthorize) before validation (@Valid) in my Controller?

此外,也许还有一种不同的方法 - 尝试通过在 @InitBinder 中注册自定义验证器来使用验证(因此跳过 @valid 注释)。

访问过滤器中的主体对象 class:

  SecurityContextImpl sci = (SecurityContextImpl)     
session().getAttribute("SPRING_SECURITY_CONTEXT");

if (sci != null) {
    UserDetails cud = (UserDetails) sci.getAuthentication().getPrincipal();

 }

在这种情况下,/{id} 是 URL 中的路径参数。访问过滤器或拦截器中的路径参数 class:

String[] requestMappingParams =    ((HandlerMethod)handler).getMethodAnnotation(RequestMapping.class).params()

        for (String value : requestMappingParams) {.

我遇到了同样的问题,我发现了这个 post。 M. Deinum 的评论帮助我理解出了什么问题

这是我所做的:

  1. public 方法有 @PreAuthorize 并进行检查
  2. @RequestBody参数上有NO@Valid
  3. 我创建了第二个私有方法,我在其中执行 DTO 验证。使用@Valid 注解
  4. public 方法将调用委托给私有方法。私有方法只有在public方法被授权
  5. 时才会被调用

示例:

@RequestMapping(method = RequestMethod.POST)
@PreAuthorize("hasRole('MY_ROLE')")
public ResponseEntity createNewMessage(@RequestBody CreateMessageDTO createMessageDTO) {
    // The user is authorized
    return createNewMessageWithValidation(createMessageDTO);
}

private ResponseEntity createNewMessageWithValidation(@Valid CreateMessageDTO createMessageDTO) {
   // The DTO is valid
   return ...
}

使用WebSecurityConfigurerAdapter.configure(HttpSecurity http)代替@PreAuthorize

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
  @Override
  protected void configure(HttpSecurity http) throws    Exception {
    http
      .authorizeRequests()
      .mvcMatchers( "/path/**").hasRole("admin");
  }
}