You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 13:44:59