Spring Security仅认证GET请求,POST/PUT/DELETE返回401错误排查
问题分析与解决方案
问题根源
你遇到的401错误并非角色权限配置问题,而是CSRF保护拦截了非GET请求。Spring Security 6中,csrf(Customizer.withDefaults())会默认启用CSRF防护机制,对于POST/PUT/DELETE这类修改型请求,要求请求必须携带CSRF令牌才能通过验证。如果请求中没有携带该令牌,无论角色权限是否匹配,都会直接返回401未授权。
这就导致了:
- EMPLOYEE角色的POST请求还没走到权限校验环节,就被CSRF拦截返回401,而非预期的403
- MANAGER/ADMIN角色的写请求同样因为缺少CSRF令牌被拦截
解决方案
根据你的接口类型选择对应方案:
方案1:REST API场景(无前端页面,供客户端调用)
如果你的接口是纯REST API,不需要支持浏览器页面发起的请求,直接禁用CSRF保护即可(CSRF攻击仅针对浏览器环境)。修改filterChain配置:
@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ // 角色权限配置保持不变 http.authorizeHttpRequests(configure -> configure .requestMatchers(HttpMethod.GET , "/api/employees").hasRole("EMPLOYEE") .requestMatchers(HttpMethod.GET , "/api/employees/**").hasRole("EMPLOYEE") .requestMatchers(HttpMethod.POST , "/api/employees").hasRole("MANAGER") .requestMatchers(HttpMethod.PUT , "/api/employees").hasRole("MANAGER") .requestMatchers(HttpMethod.DELETE , "/api/employees/**").hasRole("ADMIN") ); // 禁用CSRF保护,适配REST API场景 http.csrf(csrf -> csrf.disable()) .httpBasic(Customizer.withDefaults()); return http.build(); }
修改后测试效果:
- EMPLOYEE角色发送POST请求会正确返回403(权限不足)
- MANAGER/ADMIN角色的POST/PUT/DELETE请求可正常执行
方案2:带前端页面的场景
如果你的接口需要支持浏览器页面发起的请求,需让前端在非GET请求中携带CSRF令牌:
- Spring Security默认会将CSRF令牌存入名为
XSRF-TOKEN的Cookie中 - 前端需读取该Cookie值,并在请求头中添加
X-XSRF-TOKEN字段,值为Cookie中的令牌内容
比如用Axios发起请求的示例:
import axios from 'axios'; // 读取Cookie中的XSRF-TOKEN function getCookie(name) { let value = "; " + document.cookie; let parts = value.split("; " + name + "="); if (parts.length === 2) return parts.pop().split(";").shift(); } axios.interceptors.request.use(config => { if (config.method !== 'get') { config.headers['X-XSRF-TOKEN'] = getCookie('XSRF-TOKEN'); } return config; });
内容的提问来源于stack exchange,提问作者jerin sifat
相关产品推荐
相关产品推荐

