这是我的控制器代码:
@PreAuthorize("hasRole('CREATE_USER')")
@RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public UserReturnRO createUser(@Valid @RequestBody UserRO userRO) throws BadParameterException{
return userService.createUser(userRO);
}
我需要的是,当没有相应角色的客户端尝试创建用户时,即使发送的数据无效,控制器也会响应“未授权”。而不是那样,如果客户端(没有适当的角色)试图创建一个错误数据的用户,我的控制器会响应@Valid消息(例如:“密码不能为空”),而我希望它响应“未授权” 。
在PreAuthorized
界面中我们可以找到这句话:
用于指定方法访问控制表达式的注释,该表达式将被评估以决定是否允许方法调用。
但似乎并非如此。
答案 0 :(得分:2)
您不能直接执行此操作,因为{<1}}在实际方法调用之前处理,因此之前 @Valid
处理。
但是,您可以做的是在您的模型(userRO)之后立即注入@PreAuthorize
并执行此操作 - 控制验证过程。然后检查BindingResult
是否有错误,如果是,则返回错误的请求响应(类似于spring)。
示例:
BindingResult
答案 1 :(得分:0)
如前所述,Spring Security的@PreAuthorize
是方法建议,这意味着直到方法及其参数已解决之前,它都无法参与。
除了the answer already given以外,还有几种方法可以将授权移至参数解析之前。
首先,Spring Security在将请求映射到方法之前检查URL。并且由于这是@Controller
,因此可以合理地假设您可以将请求映射到该级别的角色,而不是@PreAuthorize
:
http
.authorizeRequests()
.mvcMatchers(POST, "/somepath").hasRole("CREATE_USER")
第二,Spring MVC确实在分析方法参数之前对检查权限的支持有限。例如,您可以执行以下操作:
@EnableWebMvc
public static class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
UserRoleAuthorizationInterceptor userRole =
new UserRoleAuthorizationInterceptor();
userRole.setAuthorizedRoles("CREATE_USER");
registry.addInterceptor(userRole);
}
}
这是@PreAuthorize
的基础,因为它是全局设置,但出于完整性考虑,我将其包括在内。
第三步(警告,请稍加保留),您可以创建自己的HandlerInterceptor
。
流为:
FilterSecurityInterceptor
<== .mvcMatchers(...).hasRole(...)
居住的地方HandlerInterceptor
s MethodSecurityInterceptor
<== @PreAuthorize
居住的地方因此,您的HandlerInterceptor
将在解析参数之前进行检查。但是,它不必像MethodSecurityInterceptor
那样参与其中。例如,它可能只是:
static class AuthorizationInterceptor extends HandlerInterceptorAdapter {
SecurityMetadataSource securityMetadataSource;
AccessDecisionManager accessDecisionManager;
@Override
public void preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
Authentication authenticated = (Authentication) request.getUserPrincipal();
MethodInvocation mi = convert(handler);
Collection<ConfigAttribute> attributes =
this.securityMetadataSource.getAttributes(mi);
// throws AccessDeniedException
this.accessDecisionManager.decide(authenticated, mi, attributes);
return true;
}
}
然后将其与以下电线连接在一起:
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodConfig extends GlobalMethodSecurityConfiguration {
@Bean
HandlerInterceptor preAuthorize() throws Exception {
return new AuthorizationInterceptor(
accessDecisionManager(), methodSecurityMetadataSource());
}
}
@EnableWebMvc
public static class MvcConfig implements WebMvcConfigurer {
@Autowired
AuthorizationInterceptor authorizationInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authorizationInterceptor);
}
}
这很不礼貌,因为MethodSecurityInterceptor
仍会参与授权的请求,表面上将是大多数请求。