我有一个使用 Spring Security OAuth2 保护的 Spring Boot 3.4 服务。
我的安全配置是标准的:
@Bean
public SecurityFilterChain oauth2FilterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(sm -> sm.sessionCreationPolicy(STATELESS))
.exceptionHandling(eh -> eh.authenticationEntryPoint(handleException()));
http.securityMatcher("/api/**")
.authorizeHttpRequests(auth ->
auth.requestMatchers("/api/**").authenticated())
.oauth2ResourceServer(resourceServer ->
resourceServer.jwt(jwt -> jwt.decoder(jwtDecoder())));
return http.build();
}
我的端点带有以下注释:@PreAuthorize(hasAuthority('SCOPE_MY_SCOPE'))
。
此外,在我的 API 模型上,我使用 Jakarta Validation 3 进行验证(例如,在字段上使用注释@NotNull
)。
鉴于此配置,我有以下场景:我使用没有所需范围的安全承载令牌发出无效请求。
服务器响应 400,因为验证约束失败。但是,我预计这个请求会返回 403;我认为 Spring 向未经授权调用我的端点的人公开了有关我的验证约束的不必要信息。如果我使用有效的请求,它确实会返回 403,所以问题在于检查的顺序:我希望先看到安全检查,然后是验证检查,但似乎情况正好相反。
对此你无能为力。首先,Spring Security 会进行请求检查( 的一部分
SecurityFilterChain
)。接下来,控制权将移交给 ,RequestMappingHandlerAdapter
它会检查方法、查看@Valid
注释并首先进行验证。如果一切顺利,它会调用 ,此时MethodSecurityInterceptor
将被调用来处理安全性。由于MethodSecurityInterceptor
依赖于正在执行的方法(它是一个前置方面),因此它不会在那之前被调用。唯一的解决方案是在您的控制器中进行手动验证。您可以通过将验证器注入控制器并自行调用来实现这一点。缺点是您也会丢失错误翻译等。
您能给出任何无效 JWT 的示例吗?如果您收到 400 代码,则您的 JWT 令牌可能格式不正确。例如;
此令牌没有“write:data”权限。但如果你发送
此令牌可能被视为格式错误。