从Angular客户端访问Spring Authorization Server /oauth2/token时遇CORS问题
问题背景
用Spring Authorization Server配合Angular客户端实现SSO时,Postman能正常获取授权码、JWT令牌及刷新令牌,但Angular向/oauth2/token发起请求时触发CORS错误。/hello这类自定义端点CORS正常,自定义CORSFilter在该端点能正确设置响应头,但/oauth2/token响应中无Access-Control-Allow-Origin头。
浏览器报错:
Access to XMLHttpRequest at 'https://domain/name/oauth2/token?client_id=clientid&redirect_uri=https://redirect/uri&grant_type=authorization_code&code=x5qQ7-####&code_verifier=codeverifier4RA' from origin 'https://client2' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
问题原因
- 过滤器链优先级冲突:Spring Authorization Server自带的SecurityFilterChain优先级(默认
@Order(0))高于你自定义的@Order(2)过滤器链,/oauth2/token请求会被框架默认链处理,你的CORS配置根本没生效。 - 自定义过滤器冗余且无效:同时使用自定义
CORSFilter和Spring Security原生CORS配置,不仅可能冲突,且自定义过滤器未必能拦截到授权服务器的端点请求。 - 请求方式不符合规范:你当前用GET请求传递令牌参数,不符合OAuth2规范(
/oauth2/token要求POST请求,参数以表单形式提交),这也可能触发额外的安全拦截。
解决方案
1. 调整过滤器链优先级,覆盖授权服务器端点
创建优先级更高的SecurityFilterChain专门处理授权服务器端点,并配置CORS:
@Bean @Order(0) public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { // 应用授权服务器默认安全配置 OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); // 为授权服务器端点绑定CORS配置 http.cors(cors -> cors.configurationSource(corsConfigurationSource())); return http.build(); }
2. 删除自定义CORSFilter
Spring Security的原生CORS机制足够处理跨域需求,自定义过滤器会干扰流程,直接删除CORSFilter类及相关注册代码。
3. 修正CORS配置细节
确保CorsConfigurationSource的配置精确匹配客户端信息:
@Bean public CorsConfigurationSource corsConfigurationSource() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); // 精确匹配客户端Origin,启用allowCredentials时不能用* config.addAllowedOrigin("https://client2"); // 允许所有必要的HTTP方法 config.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "DELETE", "PUT", "PATCH")); // 允许所有请求头 config.addAllowedHeader("*"); // 允许携带凭证(如Cookie) config.setAllowCredentials(true); // 对所有端点应用该配置 source.registerCorsConfiguration("/**", config); return source; }
4. 修正Angular请求方式
按OAuth2规范改用POST请求,参数以表单形式提交:
import { HttpClient, HttpHeaders, URLSearchParams } from '@angular/common/http'; // 在组件/service中发起请求 getToken(code: string, codeVerifier: string) { const body = new URLSearchParams(); body.set('client_id', 'clientid'); body.set('redirect_uri', 'https://redirect/uri'); body.set('grant_type', 'authorization_code'); body.set('code', code); body.set('code_verifier', codeVerifier); const headers = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }); return this.http.post('https://domain/name/oauth2/token', body.toString(), { headers }); }
验证步骤
- 重启Spring Authorization Server服务
- 用Angular发起修正后的POST请求
- 检查浏览器开发者工具的响应头,确认存在
Access-Control-Allow-Origin: https://client2
内容的提问来源于stack exchange,提问作者Bhushan Rohankar

