如前所述,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 基本得多,因为它是一个全局设置,但为了完整起见,我将其包含在内。
处理程序拦截器,第 2 部分
第三(警告,前面有些不雅),您可以创建自己的HandlerInterceptor。
流程是:
-
FilterSecurityInterceptor .mvcMatchers(...).hasRole(...) 生活在哪里
- 然后
HandlerInterceptors
- 然后是参数验证
- 然后
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 仍会参与授权请求,而这表面上是大多数。