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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:27:17