使用Fetch API发送POST请求时如何在SpringSecurity环境下正确认证
你认为设置credentials: 'include'可以携带已生效认证凭证的认知是正确的:同域请求下默认就会携带认证Cookie,跨域场景下显式设置为include才会携带认证相关的Cookie和头信息。
你的请求存在3个核心问题
- 参数不匹配+请求体格式错误:你的Controller通过
@RequestParam接收表单格式参数,要求参数名必须是someValue、userId,但你传的参数名是some、values,同时直接将JS对象传入body,Fetch不会自动序列化该对象为后端可识别的表单格式,后端无法正常解析参数直接返回403。 - 路径错误:你使用的相对路径
sm/resrc/pth会根据当前页面路径拼接,若当前页面不在根路径下会导致请求路径错误,触发权限校验失败。 - 缺少CSRF Token:Spring Security默认开启CSRF防护,表单提交时如果没有带
_csrf也能成功,大概率是测试时的缓存或临时配置问题,JavaScript异步请求默认不会自动携带CSRF Token,会直接被安全框架拦截返回403。
修复方案
1. 修正参数、请求格式与路径
将请求参数转换为后端可识别的FormData或URL编码格式,参数名与Controller保持一致,使用绝对路径:
// 方式1:使用FormData(无需手动设置Content-Type) const formData = new FormData(); formData.append('someValue', 'abc'); // 和@RequestParam参数名一致 formData.append('userId', userId); fetch("/sm/resrc/pth", { method: 'POST', credentials: 'include', body: formData }).then(response => console.log(response));
2. 配置CSRF Token携带逻辑
首先在Thymeleaf页面的head中加入CSRF信息的meta标签:
<meta name="_csrf" th:content="${_csrf.token}"> <meta name="_csrf_header" th:content="${_csrf.headerName}">
修改Fetch请求,在头信息中加入CSRF Token:
const csrfToken = document.querySelector('meta[name="_csrf"]').content; const csrfHeader = document.querySelector('meta[name="_csrf_header"]').content; const formData = new FormData(); formData.append('someValue', 'abc'); formData.append('userId', userId); fetch("/sm/resrc/pth", { method: 'POST', credentials: 'include', headers: { [csrfHeader]: csrfToken }, body: formData }).then(response => console.log(response));
如果确认不需要CSRF防护(仅前后端分离纯接口场景),也可以在Spring Security配置类中关闭CSRF:
@Configuration public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); // 其余配置保持不变 } }
内容的提问来源于stack exchange,提问作者Kerem
相关产品推荐
相关产品推荐

