Spring4.3+OAuth2跨域问题求助:AJAX请求令牌报CORS错误
解决Spring OAuth2 /oauth/token端点的CORS跨域问题
看起来你遇到的核心问题是:Spring Security OAuth2的/oauth/token端点没有被你的CORS配置覆盖,这个端点属于授权服务器的管辖范围,不在普通的WebMvc或Spring Security过滤链里,所以你之前的配置都没生效。另外你的CORS配置还有一个违反浏览器规范的冲突点,我一步步给你解决:
问题1:CORS配置的Origin与Credentials冲突
你的CorsConfiguration里同时设置了setAllowedOrigins(Arrays.asList("*"))和setAllowCredentials(true),这在浏览器中是不允许的——当请求的credentials模式为include时,Access-Control-Allow-Origin不能是通配符*,必须指定具体的客户端域名。
修正CORS配置Bean
@Bean public CorsConfigurationSource corsConfigurationSource() { final CorsConfiguration configuration = new CorsConfiguration(); // 替换成你的客户端实际地址(比如你报错里的http://localhost:8080) configuration.setAllowedOrigins(Arrays.asList("http://localhost:8080")); configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH","OPTIONS")); configuration.setAllowCredentials(true); configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type")); // 暴露OAuth2响应中可能需要的头信息(可选,但建议加上) configuration.setExposedHeaders(Arrays.asList("Authorization")); final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; }
问题2:/oauth/token端点未被CORS过滤器覆盖
/oauth/token是Spring Security OAuth2授权服务器的核心端点,它的请求处理链独立于普通的Spring Security过滤链,所以你需要在授权服务器的配置中专门添加CORS过滤器。
添加授权服务器配置类
创建一个AuthorizationServerConfig类,把CORS过滤器绑定到token端点:
@Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { private final AuthenticationManager authenticationManager; private final CorsConfigurationSource corsConfigurationSource; // 构造注入所需Bean public AuthorizationServerConfig(AuthenticationManager authenticationManager, CorsConfigurationSource corsConfigurationSource) { this.authenticationManager = authenticationManager; this.corsConfigurationSource = corsConfigurationSource; } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { // 允许表单方式获取token(适配password模式) security.allowFormAuthenticationForClients(); // 给/oauth/token端点添加CORS过滤器 security.addTokenEndpointAuthenticationFilter(new CorsFilter(corsConfigurationSource)); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // 这里配置你的客户端信息,要和你AJAX请求中的Basic认证对应 clients.inMemory() .withClient("oauthCrud") // 对应你Authorization头里的b2F1dGhDcnVk(base64解码后的值) .secret("oauthSuperSecret") // 对应Authorization头里的om9hdXRoU3VwZXJTZWNyZXQ= .authorizedGrantTypes("password", "refresh_token") .scopes("read", "write"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // 绑定AuthenticationManager用于密码模式认证 endpoints.authenticationManager(authenticationManager); } }
修正SecurityConfig,暴露AuthenticationManagerBean
在你的SecurityConfig中添加authenticationManagerBean方法,让授权服务器能获取到认证管理器:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { // 暴露AuthenticationManagerBean给授权服务器使用 @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override @Order(Ordered.HIGHEST_PRECEDENCE) protected void configure(HttpSecurity http) throws Exception { http.cors().and() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .csrf().disable() // REST API建议禁用CSRF,尤其是OAuth2 password模式 .authorizeRequests() // 批量放行无需认证的端点 .antMatchers("/register", "/contact", "/signup", "/oauth/**").permitAll() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() .anyRequest().authenticated() .and() .httpBasic(); } }
调整客户端AJAX请求
添加xhrFields.withCredentials,确保浏览器能正确处理凭证(和服务端的allowCredentials(true)对应):
var settings = { "async": true, "crossDomain": true, "xhrFields": { "withCredentials": true }, "url": "http://10.10.1.13:8080/OauthCrud/oauth/token", "method": "POST", "headers": { "authorization": "Basic b2F1dGhDcnVkOm9hdXRoU3VwZXJTZWNyZXQ=", "content-type": "application/x-www-form-urlencoded", "cache-control": "no-cache" }, "data": { "username": "rama", "password": "rama", "grant_type": "password" } } $.ajax(settings).done(function (response) { console.log(response); });
验证步骤
- 重启服务端应用
- 重新发起AJAX请求,检查浏览器控制台是否还存在CORS错误
- 如果还有问题,可以查看浏览器的Network面板,检查OPTIONS预请求的响应头是否包含正确的
Access-Control-Allow-Origin、Access-Control-Allow-Methods等字段
内容的提问来源于stack exchange,提问作者dnvsp
相关产品推荐
相关产品推荐

