Spring Boot POST请求返回403 Forbidden,GET请求正常的问题求助
问题:POST请求返回403 Forbidden,但GET请求正常(已启用Google OAuth2登录)
我正在开发一个用于练习Java的简易待办列表应用,目前已启用Google登录功能,但遇到如下问题:前端发送POST请求POST http://localhost:3000/api/v1/list/create时返回403 (Forbidden)错误,而GET请求可正常返回200 OK。
相关代码与配置
ListController代码
package com.taskboard.app.controller; import com.taskboard.app.model.Lists; import com.taskboard.app.service.ListsService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.rmi.ServerException; import java.util.List; import java.util.Optional; @RestController @RequestMapping("/api/v1/list") public class ListController { private final ListsService listsService; public ListController(ListsService listsService) { this.listsService = listsService; } @PostMapping( path = "/create", consumes = "application/json", produces = "application/json" ) public ResponseEntity<Lists> createList(@RequestBody Lists list) throws ServerException { Lists newlist = listsService.createList(list); if (newlist == null) { throw new ServerException("List not created"); } else { return new ResponseEntity<>(newlist, HttpStatus.CREATED); } } @GetMapping(path = "/all", produces = "application/json") public List<Lists> getAllLists() { System.out.println("printing name from getall lists"); return listsService.getAllLists(); } @GetMapping(path = "{id}") public Optional<Lists> getList(@PathVariable("id") String id) { return listsService.getList(id); } }
UserController代码
// create a UserController package com.taskboard.app.controller; import com.taskboard.app.model.User; import com.taskboard.app.service.UserService; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.view.RedirectView; import java.util.List; import java.util.Map; @RestController @RequestMapping("/api/v1/user") public class UserController { private Map userDetails; private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @GetMapping("/all") public List<User> getAllUsers() { return userService.getAllUsers(); } @GetMapping public Object login (OAuth2AuthenticationToken oAuth2AuthenticationToken) { userDetails = oAuth2AuthenticationToken.getPrincipal().getAttributes(); return new RedirectView("http://localhost:3000"); } @GetMapping("/current") public Object currentUser(OAuth2AuthenticationToken oAuth2AuthenticationToken) { userDetails = oAuth2AuthenticationToken.getPrincipal().getAttributes(); return userDetails; } }
application.properties配置
spring.datasource.url=jdbc:postgresql://localhost:5432/taskboard spring.datasource.username=<username> spring.datasource.password=<password> spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect spring.security.oauth2.client.registration.google.client-id=<client-id-here> spring.security.oauth2.client.registration.google.client-secret=<client-secret-here>
前端请求代码
export async function postList(list) { return await axios.post('/api/v1/list/create', list).then((response) => response.data).catch((error) => console.error(error)) }
解决思路与方案
问题核心原因:Spring Security默认对非GET请求强制校验CSRF令牌,你当前的配置中没有处理CSRF令牌的传递,且缺少明确的Security权限配置,导致POST请求被拦截返回403。
方案1:正确处理CSRF令牌(生产环境推荐)
后端配置
创建Spring Security配置类,开放必要接口并配置CSRF令牌的Cookie传递:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.csrf.CookieCsrfTokenRepository; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http // 配置接口权限 .authorizeHttpRequests(auth -> auth .requestMatchers("/oauth2/**", "/login/**", "/api/v1/user/current").permitAll() .anyRequest().authenticated() ) // 配置OAuth2登录跳转 .oauth2Login(oauth2 -> oauth2 .defaultSuccessUrl("http://localhost:3000", true) ) // 配置CSRF令牌通过Cookie传递,允许前端读取 .csrf(csrf -> csrf .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) ); return http.build(); } }
前端修改
开启Cookie携带,并从Cookie中提取CSRF令牌添加到请求头:
import axios from 'axios'; // 允许axios携带Cookie axios.defaults.withCredentials = true; export async function postList(list) { // 从Cookie中提取XSRF-TOKEN const getCookie = (name) => { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; }; const xsrfToken = getCookie('XSRF-TOKEN'); return await axios.post('/api/v1/list/create', list, { headers: { 'X-XSRF-TOKEN': xsrfToken } }).then(res => res.data).catch(err => console.error(err)); }
方案2:临时禁用CSRF(仅开发测试用)
如果只是开发阶段快速验证功能,可以临时关闭CSRF校验,但生产环境必须开启:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/oauth2/**", "/login/**").permitAll() .anyRequest().authenticated() ) .oauth2Login(oauth2 -> oauth2 .defaultSuccessUrl("http://localhost:3000", true) ) .csrf(csrf -> csrf.disable()); // 禁用CSRF return http.build(); } }
额外检查点
- 确认前端开启了
withCredentials,确保登录状态的Cookie能传递到后端 - 验证用户是否已完成Google登录,未登录状态下所有需要认证的接口都会返回403
内容的提问来源于stack exchange,提问作者jgrewal
相关产品推荐
相关产品推荐

