所有的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();
    }
}