如何使@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 的评论帮助我理解出了什么问题
这是我所做的:
- public 方法有 @PreAuthorize 并进行检查
- @RequestBody参数上有NO@Valid
- 我创建了第二个私有方法,我在其中执行 DTO 验证。使用@Valid 注解
- public 方法将调用委托给私有方法。私有方法只有在public方法被授权
时才会被调用
示例:
@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");
}
}
我正在使用 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 的评论帮助我理解出了什么问题
这是我所做的:
- public 方法有 @PreAuthorize 并进行检查
- @RequestBody参数上有NO@Valid
- 我创建了第二个私有方法,我在其中执行 DTO 验证。使用@Valid 注解
- public 方法将调用委托给私有方法。私有方法只有在public方法被授权 时才会被调用
示例:
@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");
}
}