Spring Security+CORS环境下前端获取Authorization Token为undefined求助
问题
Vue.js客户端获取Token时显示undefined,但启用Moesif CORS Chrome扩展后可正常获取。已尝试以下操作但未解决:
- 启用全局CORS配置无效
- Chrome开发者工具Network面板可见Authorization响应头包含Token,但前端仍为
undefined - 修改前端代码后问题依旧
后端Spring Security配置代码
import java.util.Arrays; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfigurationSource; //import org.springframework.web.servlet.config.annotation.CorsRegistry; //import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import lombok.AllArgsConstructor; @Configuration @AllArgsConstructor public class WebSecurityConfig { @Autowired private UserDetailsService userDetailsService; @Autowired private JWTAuthorizationFilter jwtAuthorizationFilter; @Bean SecurityFilterChain filterChain(HttpSecurity http, AuthenticationManager authManager) throws Exception { JWTAuthenticationFilter jwtAuthenticationFilter = new JWTAuthenticationFilter(); jwtAuthenticationFilter.setAuthenticationManager(authManager); jwtAuthenticationFilter.setFilterProcessesUrl("/login"); return http .csrf().disable() .cors(Customizer.withDefaults()) .authorizeRequests() .requestMatchers("/datatable").authenticated() .anyRequest().permitAll() .and() .httpBasic() .and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilter(jwtAuthenticationFilter) .addFilterBefore(jwtAuthorizationFilter, UsernamePasswordAuthenticationFilter.class) .build(); } @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("http://localhost:5173")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } @Bean AuthenticationManager authManager(HttpSecurity http)throws Exception { return http .getSharedObject(AuthenticationManagerBuilder.class) .userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()) .and() .build(); } @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } //@Bean //public WebMvcConfigurer corsConfigurer() { //return new WebMvcConfigurer() { // @Override // public void addCorsMappings(CorsRegistry registry) { // registry.addMapping("/**") //.allowedOrigins("http://localhost:5173") //.allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS") //.allowedHeaders("Authorization", "Content-Type") //.allowCredentials(true); // } //}; //} //public static void main(String[] args) { //System.out.println("pass:" + new BCryptPasswordEncoder().encode("******")); //} }
前端Vue.js+Axios代码
<script> import axios from 'axios'; export default { data() { return { formulario: { email: '', password: '' }, token: '' }; }, methods: { login() { axios.post('http://localhost:8080/login', this.formulario) .then(response => { this.token = response.headers['authorization']; localStorage.setItem('token', this.token); console.log(response.headers['authorization']); console.log('Token recibido:', this.token); }) .catch(error => { console.error('Error iniciando sesión', error); }); } } }; </script>
解决方案
问题根源
浏览器CORS机制默认仅暴露简单响应头(如Cache-Control、Content-Type),Authorization属于非简单响应头,必须在后端明确配置暴露规则,前端才能通过Axios获取到该头信息。Moesif扩展会自动补全该配置,因此启用后可正常获取。
修复步骤
1. 修改后端CORS配置
在corsConfigurationSource方法中添加exposedHeaders配置,指定暴露Authorization头:
@Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("http://localhost:5173")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type")); // 新增:暴露Authorization响应头给前端 configuration.setExposedHeaders(Arrays.asList("Authorization")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; }
2. 前端Axios优化(可选)
显式声明withCredentials: true,与后端allowCredentials配置对应,避免跨域凭据问题:
login() { axios.post('http://localhost:8080/login', this.formulario, { withCredentials: true }) .then(response => { this.token = response.headers['authorization']; localStorage.setItem('token', this.token); console.log(response.headers['authorization']); console.log('Token recibido:', this.token); }) .catch(error => { console.error('Error iniciando sesión', error); }); }
验证
重启后端服务后发起登录请求,前端可直接获取Authorization头中的Token,无需依赖CORS扩展。
内容的提问来源于stack exchange,提问作者Jannyed
相关产品推荐
相关产品推荐

