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

Spring Boot接口执行成功后返回403错误排查求助

Spring Security中/api/chat接口执行正常但返回403的问题

开发了/api/chat接口,调用时会向OpenAI API发起请求(API密钥有效且已付费)。测试流程如下:

  • 先调用/auth/login接口获取有效的JWT登录令牌,该令牌在其他所有接口中均能正常工作
  • 将令牌填入/api/chat请求的Authorization头中,通过Postman发送请求

问题现象

发起/api/chat请求后,Postman耗时约1.5-2秒处理:

  1. 前1秒内,IntelliJ运行控制台记录请求发起的正确日志
  2. 剩余时间打印OpenAI API返回的预期响应,日志显示执行完全正常
    但Postman及前端网站最终收到的是403响应,而非200 OK,导致无法提取响应内容,网站判定请求完全失败。

临时方案(不可行)

在SecurityConfig中将/api/chat设为公开接口(加入.permitAll()列表),此时接口执行流程不变,能正常返回200 OK,但会导致付费接口被公开访问,存在安全风险。

已排查内容

  • 验证JWT认证逻辑无问题
  • 确认令牌有效性
  • 排查CORS和CSRF问题,均无结果
    推测问题出在Spring Security层面,因为仅开放接口权限就能正常返回。

本人是Spring新手,恳请指点。API密钥已配置在环境变量中,日志仅打印预期响应,无错误信息。


相关代码

SecurityConfig 配置

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

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

Postman 请求示例

{
  "input": "MY INPUT"
}

内容的提问来源于stack exchange,提问作者vbsc

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 00:45:22