Spring Security使用@PreAuthorize时返回状态码26而非403问题排查
问题:无权限请求超时并返回状态码26的排查与解决
我正在开发一个将React前端与Spring Data Rest后端打包为Jar的小型项目,两者均由Spring Security保护,采用默认表单登录配置,并在Repository方法上使用@PreAuthorize注解(如@PreAuthorize("hasRole('ADMIN')"))。登录后,用户有权限时请求正常;无权限时请求会长时间等待(数分钟),最终返回HTTP状态码26。
Spring Boot版本为2.7.0。尝试过使用spring-session-jdbc和X-Auth-Token头,问题依旧。
安全配置代码
@EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) @Configuration public class SecurityConfiguration { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeRequests().anyRequest().authenticated() .and() .csrf().disable() .cors(Customizer.withDefaults()) .formLogin(); return http.build(); } @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.addAllowedHeader("*"); configuration.addAllowedMethod("*"); configuration.addAllowedOrigin("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/api/**", configuration); return source; } }
Repository端点代码
public interface UserRepository extends JpaRepository<User, String> { @PreAuthorize("hasRole('ADMIN')") <S extends User> S save(User u); @PreAuthorize("hasRole('USER')") List<User> findByNameContains(String name); }
测试请求及响应
请求命令
curl -X POST -H 'Content-Type: application/json; charset=utf8;' -i 'http://xxxxxxxxxxxx:8080/api/users' --data '{ "username": "john.m", "name": "John Murdoch" }'
响应头
Status Code: 26 access-control-allow-origin: * cache-control: no-cache, no-store, max-age=0, must-revalidate connection: keep-alive date: Mon, 10 Oct 2022 00:58:34 GMT expires: 0 keep-alive: timeout=60 pragma: no-cache vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers x-content-type-options: nosniff x-frame-options: DENY x-xss-protection: 1; mode=block
问题根源与解决
排查后发现问题出在全局异常处理器上:之前配置了一个全局异常处理器处理AccessDeniedException,移除该配置后,响应恢复为正常的403状态码。
异常处理器代码如下:
@ControllerAdvice public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler { @ExceptionHandler({ AccessDeniedException.class }) public ResponseEntity<Object> handleAccessDeniedException(Exception ex, WebRequest request) { return new ResponseEntity<Object>( ex.getLocalizedMessage(), new HttpHeaders(), HttpStatus.FORBIDDEN.ordinal()); } ... }
内容的提问来源于stack exchange,提问作者yjli
相关产品推荐
相关产品推荐

