React请求Spring Boot数据库因Spring Security失败,求专家排查
React请求Spring Boot后端因Spring Security认证失败排查
环境
- Spring Boot后端运行在
localhost:7979(IntelliJ默认运行器) - React应用运行在
localhost:3000(Windows系统的WSL环境)
后端Spring Security配置
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class SecurityConfig { @Resource private DataSource dataSource; @Autowired private UserDetailsService userDetailsService; @Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type")); corsConfiguration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT","OPTIONS","PATCH", "DELETE")); corsConfiguration.setAllowedOriginPatterns(List.of("*")); corsConfiguration.setAllowCredentials(true); corsConfiguration.setExposedHeaders(List.of("Authorization")); http .authorizeHttpRequests(auth -> auth .requestMatchers(HttpMethod.POST, "/api/users").permitAll() .requestMatchers("/api/authority").hasAuthority(Constants.ADMIN) .anyRequest().authenticated() ) .userDetailsService(userDetailsService) .sessionManagement(s -> s .sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) .cors() .configurationSource(request -> corsConfiguration) .and() .csrf().disable() .httpBasic(); http .headers() .frameOptions().sameOrigin(); return http.build(); } }
前端React请求代码(失败版本)
const headers = {} headers["Authorization"] = "Basic " + btoa("root:root"); const res = await fetch("http://localhost:7979/api/users", headers); console.log(res); const data = await res.json(); console.log(data);
日志信息
成功请求日志
2023-01-26T06:04:15.985+02:00 DEBUG 9708 --- [nio-7979-exec-1] o.s.security.web.FilterChainProxy : Securing GET /api/users 2023-01-26T06:04:16.069+02:00 DEBUG 9708 --- [nio-7979-exec-1] o.s.s.a.dao.DaoAuthenticationProvider : Authenticated user 2023-01-26T06:04:16.070+02:00 DEBUG 9708 --- [nio-7979-exec-1] o.s.s.w.a.www.BasicAuthenticationFilter : Set SecurityContextHolder to UsernamePasswordAuthenticationToken [Principal=gr.hua.dit.it22023_it22026.models.SecurityUserDetails@6bb270f7, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=172.20.196.70, SessionId=null], Granted Authorities=[ADMIN]] 2023-01-26T06:04:16.071+02:00 DEBUG 9708 --- [nio-7979-exec-1] o.s.security.web.FilterChainProxy : Secured GET /api/users
失败请求日志
2023-01-26T02:02:23.041+02:00 DEBUG 17932 --- [nio-7979-exec-1] o.s.security.web.FilterChainProxy : Securing GET /api/users 2023-01-26T02:02:23.042+02:00 DEBUG 17932 --- [nio-7979-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext 2023-01-26T02:02:23.042+02:00 DEBUG 17932 --- [nio-7979-exec-1] s.w.a.DelegatingAuthenticationEntryPoint : Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest] 2023-01-26T02:02:23.042+02:00 DEBUG 17932 --- [nio-7979-exec-1] s.w.a.DelegatingAuthenticationEntryPoint : No match found. Using default entry point org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint@456e1a23 2023-01-26T02:02:23.042+02:00 DEBUG 17932 --- [nio-7979-exec-1] o.s.security.web.FilterChainProxy : Securing GET /error 2023-01-26T02:02:23.042+02:00 DEBUG 17932 --- [nio-7979-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext 2023-01-26T02:02:23.042+02:00 DEBUG 17932 --- [nio-7979-exec-1] s.w.a.DelegatingAuthenticationEntryPoint : Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest] 2023-01-26T02:02:23.042+02:00 DEBUG 17932 --- [nio-7979-exec-1] s.w.a.DelegatingAuthenticationEntryPoint : No match found. Using default entry point org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint@456e1a23
请求详情
General
Request URL: http://localhost:7979/api/users Request Method: GET Status Code: 401 Remote Address: [::1]:7979 Referrer Policy: strict-origin-when-cross-origin
Response Headers
HTTP/1.1 401 Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Access-Control-Allow-Origin: http://localhost:3000 Access-Control-Expose-Headers: Authorization Access-Control-Allow-Credentials: true WWW-Authenticate: Basic realm="Realm" X-Content-Type-Options: nosniff X-XSS-Protection: 0 Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: SAMEORIGIN WWW-Authenticate: Basic realm="Realm" Content-Length: 0 Date: Thu, 26 Jan 2023 11:32:00 GMT Keep-Alive: timeout=60 Connection: keep-alive
Request Headers
GET /api/users HTTP/1.1 Accept: */* Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en;q=0.9,el-GR;q=0.8,el;q=0.7,en-US;q=0.6 Connection: keep-alive Host: localhost:7979 Origin: http://localhost:3000 Referer: http://localhost:3000/ Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-site User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 sec-ch-ua: "Not_A Brand";v="99", "Google Chrome";v="109", "Chromium";v="109" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows"
问题分析与解决
从请求详情可明确:失败请求的Request Headers中没有Authorization字段,这是认证失败的核心原因。前端fetch调用方式错误:fetch的第二个参数必须是配置对象,headers需放在该对象的headers属性内,而非直接传递headers对象。
修改后的前端代码:
const headers = {} headers["Authorization"] = "Basic " + btoa("root:root"); const res = await fetch("http://localhost:7979/api/users", { headers: headers, credentials: 'include' // 后端配置了AllowCredentials,需添加此参数确保凭证传递 }); console.log(res); const data = await res.json(); console.log(data);
后端配置无需调整:已允许Authorization头跨域传递,且/api/users的GET请求需要认证的规则正确。修改后请求会携带Authorization头,Spring Security的BasicAuthenticationFilter将正常处理认证流程,请求即可通过。
内容的提问来源于stack exchange,提问作者Ledrake
相关产品推荐
相关产品推荐

