Spring OAuth2认证:Postman正常但Vue客户端请求oauth/token返回401
看起来你遇到的是跨域预飞行请求(OPTIONS)被Spring Security拦截返回401的问题——浏览器在发送带Basic Auth的POST这类非简单请求前,会先发送OPTIONS请求做预检,而你的OAuth端点默认受Spring Security保护,OPTIONS请求没携带认证信息就被拒绝了。下面是具体的修复步骤:
1. 修正CORS配置的路径映射
你当前的CORS配置只匹配/*,只能覆盖一级路径(比如/test),但/oauth/token是二级路径,得把映射改成/**来覆盖所有路径,同时加上支持凭证的配置:
@Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 修改为/**匹配所有路径 .allowedOrigins("http://localhost:8080") .allowedHeaders("*") .allowedMethods("*") .allowCredentials(true); // 开启凭证支持,适配Basic Auth场景 } }; }
2. 配置Spring Security放行OPTIONS请求
Spring Security默认会拦截所有请求,包括OPTIONS预飞行请求,你需要在Security配置里明确放行OPTIONS,同时确保CORS过滤器优先执行:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .cors() // 启用CORS支持 .and() .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 放行所有OPTIONS预检请求 .anyRequest().authenticated(); // 保留你原有的其他Security配置 } // 如果使用OAuth2,还要在授权服务器配置里确保OPTIONS请求能通过 @Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security .allowFormAuthenticationForClients() .checkTokenAccess("isAuthenticated()") .tokenKeyAccess("permitAll()"); } } }
3. 修正Vue客户端的请求配置
你的客户端请求里有个错误:不要发送Access-Control-Allow-Origin请求头——这个头是服务器返回给浏览器的,不是客户端需要发送的。另外axios的auth字段会自动处理Basic Auth的请求头,不需要额外配置:
var params = new URLSearchParams(); params.append('grant_type', 'password'); params.append('username', 'username1'); params.append('password', 'password1'); axios({ method:'POST', baseURL: `http://localhost:8088/`, url: 'oauth/token', auth: { username:'my-trusted-client', password:'secret' }, headers: { // 移除Access-Control-Allow-Origin头 "Content-type": "application/x-www-form-urlencoded; charset=utf-8" }, data: params }).then ((response) => { console.log (response) }) .catch ((error) => { console.log (error) })
问题根源说明
当浏览器发送跨域的非简单请求(比如带Basic Auth、自定义头的POST)时,会先发送OPTIONS预飞行请求,询问服务器是否允许该跨域请求。如果这个OPTIONS请求被Spring Security拦截返回401,浏览器就会判定跨域不被允许,直接终止后续的POST请求,也就是你看到的Response for preflight has invalid HTTP status code 401错误。
按上面的步骤调整后,应该就能正常获取token了。
内容的提问来源于stack exchange,提问作者Blank

