React表单提交时Anti-CSRF Token没变化导致重复提交被拦截怎么办?
我在用React做文件上传功能时,按照教程实现了CSRF防护,但发现同一个页面多次提交时token没变,导致第二次提交被服务器拦截了。明明在组件挂载时生成了token,代码是这样的:
class FileUpload extends React.Component {
constructor() {
super();
this.state = {
csrfToken: this.generateToken()
};
}
generateToken = () => {
return Math.random().toString(36).substr(2);
};
handleSubmit = (e) => {
e.preventDefault();
const { csrfToken } = this.state;
// 发送文件和csrfToken到后端
console.log('Submitted with token:', csrfToken);
};
render() {
return (
);
}
}
问题就是每次上传完再选新文件提交时,控制台显示用的还是同一个token值,后端返回403错误。我尝试过在handleSubmit里调用generateToken重新生成,但这样会导致表单还没提交前token就变了,感觉哪里设计错了?
解决办法其实很简单,WordPress本身就有现成的CSRF防护机制,完全没必要自己手动生成token。WordPress提供了
wp_create_nonce和check_ajax_referer这两个函数专门用来处理这种情况。你只需要在前端通过WordPress的REST API或者AJAX请求获取一个动态的nonce值,然后每次提交表单时都重新请求一个新的nonce。具体实现步骤是这样的:首先在后端注册一个REST路由,用来返回新的nonce值。代码类似这样:
然后在React组件里,先在
componentDidMount里通过fetch请求这个接口拿到初始的nonce,再在每次提交表单后重新请求更新nonce。改一下你的代码:这样一来,每次提交表单后都会自动获取新的token,既解决了重复提交的问题,又利用了WordPress自带的安全机制,省得自己折腾随机数生成算法了。对了,记得在后端验证这个nonce,用
check_ajax_referer('wp_rest')就行,这是WordPress推荐的做法。handleSubmit方法:这样每次提交都用最新token,不会重复。