所有的POST请求都被SpringSecurity自带的CSRF防护给拦截,返回403。
从Spring Security 4.0开始,默认情况下会启用CSRF保护,以防止CSRF攻击应用程序,Spring Security CSRF会针对PATCH,POST,PUT和DELETE方法的请求(不仅仅只是登陆请求,这里指的是任何请求路径)进行防护,而这里的登陆表单正好是一个POST类型的请求。在默认配置下,无论是否登陆,页面中只要发起了PATCH,POST,PUT和DELETE请求一定会被拒绝,并返回403错误**(注意,这里是个究极大坑,这个没有任何提示,直接403,因此如果你不知道的话根本不清楚是什么问题,就一直卡这里了)**,需要在请求的时候加入csrfToken才行,也就是”83421936-b84b-44e3-be47-58bb2c14571a”,正是csrfToken,如果提交的是表单类型的数据,那么表单中必须包含此Token字符串,键名称为”_csrf”;如果是JSON数据格式发送的,那么就需要在请求头中包含此Token字符串。
我们在POST请求中携带页面中的csrfToken才可以,否则一律进行拦截操作,这里我们可以将其嵌入到页面中,随便找一个地方添加以下内容:
<input type="text" th:id="${_csrf.getParameterName()}" th:value="${_csrf.token}" hidden>
接着在axios发起请求时,携带这个input的value值:
function pay() {
const account = document.getElementById("account").value
const csrf = document.getElementById("_csrf").value
axios.post('/mvc/pay', {
account: account,
_csrf: csrf //携带此信息即可,否则会被拦截
}, {
...
如果后续各位小伙伴遇到那种需要再form表单中提交的情况,也可以直接像下面这样给塞到表单里:
<form action="/xxxx" method="post">
...
<input type="text" th:name="${_csrf.getParameterName()}" th:value="${_csrf.token}" hidden>
...
</form>
关闭CSRF校验
如果出现 服务器理解该请求但拒绝授权 的情况也有可能是未关闭CSRF校验。
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
...
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
...
//以下是csrf相关配置
.csrf(conf -> {
conf.disable(); //此方法可以直接关闭全部的csrf校验,一步到位
conf.ignoringRequestMatchers("/xxx/**"); //此方法可以根据情况忽略某些地址的csrf校验
})
.build();
}
}