動態

詳情 返回 返回

藍易雲:快速解決Spring Boot跨域困擾:使用CORS實現無縫跨域支持 - 動態 詳情

以下內容聚焦Spring Boot 3.x / Spring Security 6的當下實踐,幫你用最小代價拿下跨域。結論先行:前後端分離項目應將 CORS 作為“平台能力”,在MVC 層Security 層雙棧一致配置,並對預檢請求(OPTIONS)提供零阻斷通道。🚀


一、目標與原則(結論速覽)

  • 統一在 WebMvcConfigurerSecurityFilterChain 開啓 CORS,保持配置同源。
  • 對預檢請求放行;攜帶憑證時,不得使用 *,改用明確白名單域名。
  • 通過 反向代理/網關 複用規則,杜絕環境漂移。
    關鍵控制點:<span style="color:red">allowedOrigins / allowCredentials / allowedHeaders / allowedMethods / maxAge</span>。

二、代碼落地:全局 CORS(MVC 層)

// src/main/java/com/example/config/WebCorsConfig.java
@Configuration
public class WebCorsConfig implements WebMvcConfigurer {
  @Override
  public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
      .allowedOrigins("https://app.example.com", "https://admin.example.com")
      .allowedMethods("GET","POST","PUT","DELETE","PATCH","OPTIONS")
      .allowedHeaders("*")
      .exposedHeaders("X-Request-Id","X-Total-Count")
      .allowCredentials(true)
      .maxAge(3600);
  }
}

解釋:

  • addMapping("/**") 作用到全部接口;
  • allowedOrigins(...) 明確白名單,滿足 <span style="color:red">Cookie/Authorization</span> 等憑證場景;
  • allowCredentials(true) 開啓跨站憑證;
  • maxAge(3600) 預檢緩存 1 小時,降低延遲;
  • exposedHeaders(...) 讓瀏覽器可讀自定義響應頭。

三、代碼落地:Security 層放行預檢

// src/main/java/com/example/config/SecurityConfig.java
@Configuration
@EnableMethodSecurity
public class SecurityConfig {

  @Bean
  public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http
      .csrf(csrf -> csrf.disable())
      .cors(Customizer.withDefaults())   // 關鍵:啓用 CORS
      .authorizeHttpRequests(auth -> auth
        .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 關鍵:放行預檢
        .anyRequest().authenticated()
      );
    return http.build();
  }

  @Bean
  public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration cfg = new CorsConfiguration();
    cfg.setAllowedOrigins(List.of("https://app.example.com","https://admin.example.com"));
    cfg.setAllowedMethods(List.of("GET","POST","PUT","DELETE","PATCH","OPTIONS"));
    cfg.setAllowedHeaders(List.of("*"));
    cfg.setExposedHeaders(List.of("X-Request-Id","X-Total-Count"));
    cfg.setAllowCredentials(true);
    cfg.setMaxAge(3600L);

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", cfg);
    return source;
  }
}

解釋:

  • Security 默認會在 CorsFilter 前進行鏈式處理;cors(Customizer.withDefaults()) 會讀取 CorsConfigurationSource
  • 放行 OPTIONS /** 保證瀏覽器預檢不被鑑權攔截。
  • MVC 與 Security 保持同一份域名白名單,避免“走 MVC 通不過 Security”的錯配。
  • <span style="color:red">不要再使用過時的 WebSecurityConfigurerAdapter</span>。

四、局部快速解法(臨時/灰度)

// 僅在必要時對單個控制器/方法使用
@CrossOrigin(origins={"https://app.example.com"}, allowCredentials = "true",
             maxAge = 3600, exposedHeaders = {"X-Request-Id"})
@RestController
@RequestMapping("/api/users")
public class UserController { /* ... */ }

解釋:

  • 局部註解適合灰度或緊急放行;
  • 大規模項目建議仍以全局配置為主,降低維護成本與合規風險。

五、網關/代理層(可選但推薦)

// Spring Cloud Gateway (application.yml)
spring:
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedOrigins: "https://app.example.com,https://admin.example.com"
            allowedMethods: "*"
            allowedHeaders: "*"
            allowCredentials: true
            maxAge: 3600

解釋:

  • 在網關統一 CORS,可同時保護多語言後端;
  • 與後端保持同源配置,避免“代理放開/後端收緊”的割裂。

六、分析説明表(vditor/Markdown 兼容)

配置項對照表

配置項 含義 建議值 關鍵風險
<span style="color:red">allowedOrigins</span> 允許的來源域 生產用明確域名 allowCredentials=true禁止使用 *
allowedMethods 允許的方法 明確或 "*" 過度放開需配合鑑權
allowedHeaders 請求可帶的頭 "*" 或白名單 過度限制會導致預檢失敗
<span style="color:red">exposedHeaders</span> 前端可讀的響應頭 業務所需最小集 不暴露敏感頭
<span style="color:red">allowCredentials</span> 是否攜帶憑證 需要會話時設 true 搭配白名單域
<span style="color:red">maxAge</span> 預檢緩存秒數 1800–7200 太小會增大延遲

預檢處理工作流程(簡化)

  1. 瀏覽器發現跨站 → 發起 OPTIONS 預檢;
  2. 代理/網關接收並回寫 CORS 頭;
  3. Security 放行 OPTIONS,不觸發認證;
  4. MVC 返回 2xx + CORS 允許頭;
  5. 瀏覽器緩存預檢結果,在 maxAge 內直接發實際請求。✅

七、快速自檢命令與解釋

# 預檢自測:確認 204/200 + 允許頭齊全
curl -i -X OPTIONS https://api.example.com/users \
  -H "Origin: https://app.example.com" \
  -H "Access-Control-Request-Method: POST"

# 實際請求自測(帶 Cookie)
curl -i -X POST https://api.example.com/users \
  -H "Origin: https://app.example.com" \
  -H "Content-Type: application/json" \
  -H "Cookie: SESSION=xxxx" \
  --data '{"name":"alice"}'

解釋:

  • 第一個請求模擬瀏覽器預檢,關注響應頭中是否包含 <span style="color:red">Access-Control-Allow-Origin</span>、<span style="color:red">Access-Control-Allow-Credentials</span>、<span style="color:red">Access-Control-Allow-Headers</span>;
  • 第二個請求驗證攜帶憑證場景;若 302/401,説明被鑑權鏈攔截,應檢查 Security 放行策略與會話策略(如 SameSite=None; Secure)。

八、常見坑位與硬性結論

  • <span style="color:red">憑證 + “*”不可並存</span>:allowCredentials=true 時,allowedOrigins 需顯式域名。
  • <span style="color:red">重定向會吞頭</span>:接口有 301/302/307/308 時,瀏覽器可能不傳遞預期 CORS 頭,務必返回最終 2xx
  • <span style="color:red">Cookie 策略</span>:跨站會話需設置 SameSite=None; Secure,否則瀏覽器丟 Cookie。
  • <span style="color:red">代理雙寫</span>:Nginx/網關若追加 CORS 頭需與後端一致,避免衝突。
  • <span style="color:red">方法白名單與權限模型</span>:CORS 放開不等於放權;敏感接口仍以鑑權/簽名作為最後防線。🛡️

九、面向未來的治理建議

  • 將 CORS 規則沉澱為配置中心策略,按環境(dev/stage/prod)分組;
  • 建立域名白名單變更流程,引入自動化自測(curl OPTIONS)作為發佈前哨;
  • 在 API 網關處統一冪等預檢緩存策略,降低移動弱網抖動。📈

一句話總結:把 CORS 當作平台級能力,<span style="color:red">MVC 與 Security 同源配置、預檢零阻斷、憑證配白名單</span>,即可在 Spring Boot 中實現“無縫跨域”的穩定交付。💼✨

user avatar debuginn 頭像 actionopensource 頭像 yangrd 頭像 tdengine 頭像
點贊 4 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.