Spring Boot OAuth2与Angular5生成OAuth2令牌时跨域预检401报错
这问题我之前帮同事排查过,核心原因是浏览器的CORS预检请求(OPTIONS)不会携带任何认证凭证,但你的Spring Boot OAuth2服务端默认把OPTIONS请求也纳入了安全校验,直接返回401,导致Angular的正式POST请求根本发不出去。下面给你几个可行的解决思路:
1. 让Spring Boot服务端放行OPTIONS预检请求
在你的Spring Security配置类里,专门对/oauth/token的OPTIONS请求做免认证放行,同时配置正确的CORS规则:
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.http.HttpMethod; public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http // 先放行所有OPTIONS请求,避免预检被拦截 .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll() .anyRequest().authenticated() .and() // 保留你原有的OAuth2相关配置,比如oauth2ResourceServer或者formLogin等 .csrf().disable(); // 如果是前后端分离,通常需要关闭CSRF } // 配置全局CORS规则,允许前端域名跨域请求 @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); // 替换成你的Angular前端实际地址,比如http://localhost:4200 config.addAllowedOrigin("http://localhost:4200"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }
2. 调整Angular请求,符合OAuth2令牌接口要求
OAuth2的令牌接口(/oauth/token)默认要求用application/x-www-form-urlencoded格式传参,并且client_id和client_secret需要通过Basic Auth传递。你可以修改Angular代码如下:
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; // 假设这是你的登录服务方法 login2(credentials: { username: string, password: string }) { // 把client_id和client_secret做Base64编码,用于Basic认证 const clientCredentials = btoa('your_client_id:your_client_secret'); const headers = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': `Basic ${clientCredentials}` }); // 构造请求体参数,grant_type根据你的实际模式调整(比如password/authorization_code) const body = new HttpParams() .set('username', credentials.username) .set('password', credentials.password) .set('grant_type', 'password'); return this.http.post( 'http://localhost:9999/auth-service/oauth/token', body.toString(), { headers: headers, withCredentials: true } // withCredentials允许携带cookie等凭证 ); }
3. 额外注意点
- 如果你用的是Spring Boot 2.7+或者Spring Security 5.7+,
WebSecurityConfigurerAdapter已经被弃用了,需要用SecurityFilterChain来配置,核心逻辑还是放行OPTIONS请求+配置CORS - 确保你的OAuth2授权服务器配置里,允许该client_id使用password模式(如果用的是密码模式)
- 测试时可以先在浏览器控制台看OPTIONS请求的响应头,确认
Access-Control-Allow-Origin、Access-Control-Allow-Methods等CORS头是否正确返回
按这几步调整后,应该就能解决预检请求401的问题了,先从服务端放行OPTIONS请求入手,这是最常见的触发原因。
内容的提问来源于stack exchange,提问作者user9247715
相关产品推荐
相关产品推荐

