Spring Boot 端点执行成功但是返回 403

我创建了一个端点 /api/chat,调用时会向 OpenAI API(已付费且 API KEY 有效)发出另一个请求。

我在 Postman 中测试该端点,首先请求我的 /auth/login 端点以获得一个有效的 JWT Token,然后将其复制到 /api/chatAuthorization Header 中,最后发起请求(登录的
JWT Token 100% 有效,而且在所有其他端点中都没问题)。

当请求 /api/chat 时,大约需要 1.5-2 秒。在第一秒钟,IDE 控制台输出了正常的内容,表明请求已发出,接着输出 OpenAI API 的响应。到这里一切都没问题。但随后 Postman 返回的状态码是 403,而不是 200 OK,我 IDE 控制台输出的内容都没有问题。

我尝试在 SecurityConfig 中把 /api/chat 端点设置为公开的。这样倒是没问题,但是问题更大了,相当于任何人都可以访问我的 API(我的 ChatGPT 充了钱的)。

这个问题我折腾了很久,包括上网搜索、问 GPT,但一无所获。我感觉是 Spring Security 出了问题,因为只有将端点添加到 SecurityConfig 中的 .permitAll() List(公开这个端点)中,它才能返回 200 OK。

我的一一些代码如下:

Security 配置:

@Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf()
                .disable()
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/auth/**", "/", "/index.html", "/manifest.json", "/static/**", "/*.js", "/*.jsx", "/*.css", "/home", "/log-in", "/sign-up")
                        .permitAll()
                        .requestMatchers("/auth/signup", "/auth/login").anonymous()
                        .anyRequest()
                        .authenticated()
                )
                .sessionManagement(session -> session
                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                )
                .authenticationProvider(authenticationProvider)
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();

Controller:

@PostMapping
    public Mono<ResponseEntity<String>> getChatCompletion(@RequestBody ChatRequest chatRequest, @RequestHeader HttpHeaders headers) {

        return openAiService.getChatCompletion(chatRequest.getInput())
                .map(response -> {
                    logger.info("Response: {}", response); // 记录响应
                    return ResponseEntity.ok(response);
                })
                .defaultIfEmpty(ResponseEntity.noContent().build());
    }

    public static class ChatRequest {
        private String input;

        public String getInput() {
            return input;
        }

        public void setInput(String input) {
            this.input = input;
        }
    }

Service:

public Mono<String> getChatCompletion(String userInput) {
        String requestBody = String.format("""
                {
                    "model": "gpt-3.5-turbo",
                    "messages": [
                        {
                            "role": "system",
                            "content": "MY CONTENT"
                        },
                        {
                            "role": "user",
                            "content": "%s"
                        }
                    ],
                    "temperature": 1,
                    "max_tokens": 256,
                    "top_p": 1,
                    "frequency_penalty": 0,
                    "presence_penalty": 0
                }
                """, userInput);

        logger.info("Sending request to OpenAI with body: {}", requestBody);

        return this.webClient.post()
                .uri("/chat/completions")
                .header("Content-Type", "application/json")
                .header("Authorization", "Bearer " + openaiApiKey)
                .bodyValue(requestBody)
                .retrieve()
                .bodyToMono(String.class)
                .doOnNext(response -> logger.info("Received response from OpenAI: {}", response))
                .doOnError(WebClientResponseException.class, error -> {
                    logger.error("Error response from OpenAI: {}", error.getResponseBodyAsString());
                })
                .doOnError(error -> logger.error("Error occurred: ", error));
    }

我的 Postmant 请求(应该和问题没啥关系):

{
input: "MY INPUT"
}