知識庫 / Spring / Spring Security RSS 訂閱

解決401錯誤:CORS預檢和Spring Security配置

Spring Security
HongKong
5
01:28 PM · Dec 06 ,2025

1. 概述

在本簡短教程中,我們將學習如何解決“預檢請求的響應具有無效的 HTTP 狀態碼 401”錯誤,該錯誤可能出現在支持跨域通信且使用 Spring Security 的應用程序中。

首先,我們將瞭解跨域請求的概念,然後我們將修復一個問題示例。

2. 跨域請求

跨域請求,簡而言之,是指請求的源(origin)和目標(target)不同的HTTP請求。例如,當一個Web應用程序託管在一個域名下,瀏覽器向另一個域名下的服務器發送AJAX請求時,這種情況就屬於跨域請求。

為了管理跨域請求,服務器需要啓用一種機制,稱為CORS(跨域資源共享)。

CORS的第一步是發送一個OPTIONS請求,以確定目標請求是否支持它。這被稱為預檢請求。

服務器可以響應預檢請求,並返回一組頭部信息:

  • Access-Control-Allow-Origin 定義允許訪問資源的源。“*”表示任何源
  • Access-Control-Allow-Methods 指出允許的跨域請求HTTP方法
  • Access-Control-Allow-Headers 指出允許的跨域請求頭部
  • Access-Control-Max-Age 定義預檢請求結果的過期時間

因此,如果預檢請求不滿足從這些響應頭部確定的條件,則實際的跟進請求將會拋出與跨域請求相關的錯誤。

在我們的Spring驅動服務中添加CORS支持很容易,但如果配置不當,這個預檢請求將會始終返回401錯誤。

3. 創建支持 CORS 的 REST API

為了模擬問題,首先創建一個支持跨域請求的簡單 REST API:

@RestController
@CrossOrigin("http://localhost:4200")
public class ResourceController {

    @GetMapping("/user")
    public String user(Principal principal) {
        return principal.getName();
    }
}

@CrossOrigin 註解確保我們的API僅從其參數中指定的源(origin)訪問。

4. 保護我們的 REST API

現在,讓我們使用 Spring Security 來保護我們的 REST API:

@EnableWebSecurity
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry.anyRequest().authenticated())
            .httpBasic(Customizer.withDefaults());
        return http.build();
    }
}

在配置類中,我們強制執行了所有傳入請求的授權。因此,它將拒絕所有缺少有效授權令牌的請求。

5. 發送預檢請求

現在我們已經創建了 REST API,讓我們使用 curl 嘗試發送預檢請求:

curl -v -H "Access-Control-Request-Method: GET" -H "Origin: http://localhost:4200" 
  -X OPTIONS http://localhost:8080/user
...
< HTTP/1.1 401
...
< WWW-Authenticate: Basic realm="Realm"
...
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< Access-Control-Allow-Origin: http://localhost:4200
< Access-Control-Allow-Methods: POST
< Access-Control-Allow-Credentials: true
< Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
...

從該命令的輸出中可以看出,請求被拒絕,狀態碼為 401。

由於這是一個 curl 命令,因此我們不會在輸出中看到“預檢請求的響應具有無效的 HTTP 狀態碼 401”錯誤。

但是,通過創建一個從不同域消耗我們 REST API 的前端應用程序並在瀏覽器中運行它,我們可以重現這個確切的錯誤。

6. 解決方案

我們沒有在我們的 Spring Security 配置中明確排除授權預檢請求。請記住,Spring Security 默認情況下通過所有端點進行安全保護。

因此,我們的 API 期望在 OPTIONS 請求中包含授權令牌。

Spring 提供了內置的解決方案,用於排除 OPTIONS 請求的授權檢查:

@EnableWebSecurity
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        // ...
        http.cors(Customizer.withDefaults()); // disable this line to reproduce the CORS 401
        return http.build();
    }
}

cors() 方法將 Spring 提供的 CorsFilter 添加到應用程序上下文中,從而繞過 OPTIONS 請求的授權檢查。

現在我們可以再次測試我們的應用程序,並確認它正在正常工作。

7. 結論

在本文中,我們學習瞭如何修復“預檢請求的響應具有無效的 HTTP 狀態碼 401”錯誤,該錯誤與 Spring Security 和跨域請求相關。

請注意,通過示例,客户端和 API 應該在不同的域名或端口上運行,才能重現該問題。 例如,在本地機器上運行時,可以將默認主機名映射到客户端,並將機器 IP 地址映射到我們的 REST API。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.