我有一个带有POST端点的Spring Boot应用程序,@ PreAuthorize角色定义和请求正文的自定义验证器:
@PreAuthorize("hasAnyRole('ROLE_OTHER')")
@RequestMapping(value = "post", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public String post(@RequestBody @Valid DummyDTO dummyDTO) {
...
}
1)当我使用错误的角色和无效的请求正文调用端点时,会执行自定义验证代码,即ConstraintValidator.isValid(),并且得到400错误请求。
2)当我使用错误角色和有效请求正文调用端点时,会执行自定义验证代码ConstraintValidator.isValid(),并且我得到403禁
为什么在@PreAuthorize检查之前执行自定义验证代码?在这两种情况下我都希望得到403.
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : Successfully Authenticated: org.springframework.security.authentication.TestingAuthenticationToken@bbd5887f: Principal: key; Credentials: [PROTECTED]; Authenticated: false; Details: null; Granted Authorities: ROLE_USER
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@41ba74ef, returned: 1
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : Authorization successful
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor : RunAsManager did not change Authentication object
DEBUG 12776 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy : /post reached end of additional filter chain; proceeding with original chain
INFO 12776 --- [nio-8080-exec-3] com.example.DummyValidator : > isValid(): [valid]
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.a.i.a.MethodSecurityInterceptor : Secure object: ReflectiveMethodInvocation: public java.lang.String com.example.MyController.post(com.example.DummyDTO); target is of class [com.example.MyController]; Attributes: [[authorize: 'hasAnyRole('ROLE_OTHER')', filter: 'null', filterTarget: 'null']]
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.authentication.ProviderManager : Authentication attempt using org.springframework.security.authentication.TestingAuthenticationProvider
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.a.i.a.MethodSecurityInterceptor : Successfully Authenticated: org.springframework.security.authentication.TestingAuthenticationToken@bbd5887f: Principal: key; Credentials: [PROTECTED]; Authenticated: false; Details: null; Granted Authorities: ROLE_USER
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter@356a19a2, returned: -1
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.access.vote.RoleVoter@7290b3e0, returned: 0
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.access.vote.AuthenticatedVoter@16f3e525, returned: 0
DEBUG 12776 --- [nio-8080-exec-3] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
...
我的DTO:
public class DummyDTO {
@DummyConstraint
private String name;
...
}
约束:
@Documented
@Retention(RUNTIME)
@Target({TYPE, FIELD, PARAMETER, ANNOTATION_TYPE})
@Constraint(validatedBy = {DummyValidator.class})
public @interface DummyConstraint {
...
}
和验证者:
public class DummyValidator implements ConstraintValidator<DummyConstraint, String> {
private static final Logger LOGGER = LoggerFactory.getLogger(DummyValidator.class);
@Override
public void initialize(DummyConstraint constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
LOGGER.info("> isValid(): [{}]", value);
return "valid".equalsIgnoreCase(value);
}
}