成功执行后端点返回403(Spring Boot)

问题描述 投票:0回答:1

我创建了一个端点“/api/chat”,当被调用时,它会向 OpenAI API 发出另一个请求(付费且 API 密钥有效,所有这些)。在 Postman 中测试端点时,我首先请求 /auth/login 端点获取有效的 JWT 登录令牌,将其复制到 /api/chat 调用的授权标头,然后发送它(登录身份验证令牌 100% 有效) ,并且也适用于所有其他端点)。

当向 /api/chat 发出请求时,Postman 大约需要 1.5-2 秒来处理它。在第一秒,Intellij 中的运行控制台会记录正确的内容以表明正在发出请求。在剩余时间内,它会记录来自 OpenAI API 模型的确切预期响应。你可能会认为这意味着一切都执行得很好,而且看起来确实如此,但是 Postman(以及我的网站,如果你在那里尝试的话)返回 403 而不是 200 OK。这是一个问题,因为即使我可以实际看到 IDE 控制台中记录的正确响应没有错误,但 403 意味着我无法提取任何内容以供使用,并且网站无法接收它并将其视为请求完全失败。

我“修复”此问题的唯一方法是在我的 SecurityConfig 文件中公开 /api/chat 端点,这使其以完全相同的方式执行并给出相同的结果,但按预期返回 200 OK。但是,我当然不能这样保留它,因为这意味着人们可以公开访问端点,而每个请求都会花费我的费用。

我花了很多时间试图解决这个问题,包括谷歌搜索、询问 GPT - 什么也没有。验证了我所有的 JWT 身份验证内容,尝试了始终保留身份验证令牌的方法,但没有任何效果。 CORS 和 CSRF 之类的东西,似乎也不是。我只能认为它与 Spring Security 有关,因为将端点添加到 SecurityConfig 中的 .permitAll() 列表(使其公开)是唯一使其按预期返回 200 OK 的事情。这是非常令人沮丧的,因为它准确地执行和记录了它应该如何以及应该做什么,但只是出于某种原因返回 403。

这是我使用 Spring 的第一个项目,所以如果它是微不足道的,那么请帮忙。提前致谢。 API密钥在我的环境变量中设置,尽管我已经包含了一些错误日志记录,但没有记录任何错误,只有我期望从AI模型中得到的正确响应,然后它返回403,因为我已经提及。我将包含相关的代码位,但如果您认为问题出在另一个文件或这些文件的一部分中,请告诉我,我将尽我所能分享。我认为这并不是太重要,而是我正在使用 React 作为前端。

安全配置:

@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();

控制器:

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

        return openAiService.getChatCompletion(chatRequest.getInput())
                .map(response -> {
                    logger.info("Response: {}", response); // Logging 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;
        }
    }

服务:

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));
    }

我的邮递员请求(不太相关,这不是问题):

{
input: "MY INPUT"
}
java spring spring-boot openai-api http-status-code-403
1个回答
0
投票

我今天遇到了同样的奇怪行为:安全端点被调用,但在执行后返回 403 状态。

更糟糕的是,使用 MockMvc 的 JUnit 集成测试不会产生 403 状态。

拥有另一个工作端点给了我一个关于正在发生的事情的提示:

我的代码中的返回类型没有用

@ResponseBody
注释,在 Spring Boot 3.3.2 中,它在方法完成后显然会抛出异常。然后这个异常会被 Spring Security 变成 403。

(我最终将注释添加到我的

void
方法中。🤯)

© www.soinside.com 2019 - 2024. All rights reserved.