React+Spring Boot跨域时无法获取响应Authorization头,求解决方法
登录接口返回的JWT Token放在响应头的Authorization字段中,前端之前能正常读取,但后端启用Spring Security的cors()配置后,前端再也拿不到这个字段了。后端返回的响应头里确实存在Authorization字段,但前端就是访问不到。
前端登录函数代码
const username = useRef(); const password = useRef(); const navigate = useNavigate(); function loginHandler() { axios.post("/auth/login", { username: username.current.value, password: password.current.value }) .then((response) => { console.log(response.headers) window.localStorage.setItem("token", response.headers.get("Authorization")) navigate("/shoes/mens") }); }
后端Spring Security配置代码
@Override protected void configure(HttpSecurity http) throws Exception { http = http.csrf().disable().cors().and(); http = http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and(); http = http.exceptionHandling() .authenticationEntryPoint((request, response, ex) -> { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ex.getMessage()); }).and(); http.authorizeRequests() .antMatchers("/auth/**").permitAll() .antMatchers("/storage/**").hasAuthority("ROLE_EMPLOYEE") .anyRequest().authenticated(); http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); }
解决方法
问题根源是CORS的默认限制:浏览器只允许前端访问预设的CORS安全响应头(比如Content-Type、Cache-Control这些),像Authorization这种自定义头不在默认列表里,哪怕后端返回了,前端也读不到。
必须在Spring Boot的CORS配置里显式声明要暴露Authorization头,下面给两种实现方式:
方式1:全局CORS配置(@Bean)
@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); // 允许的前端域名,根据实际情况改,不要随便用*(带凭证时*无效) config.setAllowedOriginPatterns(Arrays.asList("http://localhost:3000")); // 允许的请求方法 config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); // 允许的请求头 config.setAllowedHeaders(Arrays.asList("*")); // 核心:告诉浏览器可以暴露Authorization头给前端 config.setExposedHeaders(Arrays.asList("Authorization")); // 允许携带Cookie等凭证(如果业务需要的话) config.setAllowCredentials(true); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }
方式2:在Security配置中集成CORS配置
直接修改你现有的Security配置类,把默认的.cors()换成自定义的配置源:
@Override protected void configure(HttpSecurity http) throws Exception { // 替换默认cors配置,使用自定义的配置源 http = http.csrf().disable().cors(cors -> cors.configurationSource(corsConfigurationSource())).and(); // 下面的原有配置保持不变 http = http.sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and(); http = http.exceptionHandling() .authenticationEntryPoint((request, response, ex) -> { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, ex.getMessage()); }).and(); http.authorizeRequests() .antMatchers("/auth/**").permitAll() .antMatchers("/storage/**").hasAuthority("ROLE_EMPLOYEE") .anyRequest().authenticated(); http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); } // 自定义CORS配置源 private CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOriginPatterns(Arrays.asList("http://localhost:3000")); config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); config.setAllowedHeaders(Arrays.asList("*")); config.setExposedHeaders(Arrays.asList("Authorization")); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; }
注意事项
setExposedHeaders是关键操作,必须加上才能让前端读到Authorization头。- 允许的源要根据实际前端地址设置,本地开发一般是
http://localhost:端口号,生产环境换成实际域名。 - 配置完重启后端,前端再登录就能在
response.headers里看到Authorization字段了。
内容的提问来源于stack exchange,提问作者Dusta
相关产品推荐
相关产品推荐

