Vue表单提交时如何同时实现CSRF防护和验证码验证?
在开发登录表单时,我需要同时处理CSRF防护和验证码验证。现在遇到的问题是:当用户刷新验证码时,CSRF令牌没有同步更新,导致表单提交时后端返回验证失败。我尝试在获取验证码接口里携带CSRF令牌,但发现令牌值始终是初始化时的旧值。
这是我的Vue表单组件代码:
<template>
<form @submit.prevent="submitForm">
<input v-model="formData.username">
<input v-model="formData.password">
<img :src="captchaUrl" @click="refreshCaptcha">
<input v-model="formData.code">
<button type="submit">登录</button>
</form>
</template>
<script>
export default {
data() {
return {
formData: {
username: '',
password: '',
code: '',
_csrf: '' // 从cookie获取的初始值
},
captchaUrl: <code>/api/captcha?_=${Date.now()}</code>
}
},
methods: {
refreshCaptcha() {
this.captchaUrl = <code>/api/captcha?_=${Date.now()}</code>;
},
async submitForm() {
try {
await this.$axios.post('/login', this.formData, {
headers: {'X-CSRF-Token': this.formData._csrf}
});
} catch(err) {
console.error('验证失败', err);
}
}
}
}
</script>
问题具体出现在:当我点击刷新验证码时,虽然图片更新了,但后端返回的新的CSRF令牌没有被正确捕获。我应该在哪个生命周期阶段重新获取CSRF令牌?是否需要在刷新验证码时同时更新令牌?
具体改动如下:
1. 获取验证码的接口应该返回两个值:新的CSRF令牌 + 新的验证码图片地址。比如返回结构是:
2. 修改refreshCaptcha方法,用axios请求获取新验证码和新令牌:
3. 初始化的时候也要调用一次refreshCaptcha,这样表单里的_csrf就不会是空值
4. 提交表单的时候只需要传formData,不需要额外带headers。因为后端验证CSRF时会从表单字段里取这个令牌。
这样改完就能保证每次刷新验证码时,CSRF令牌也是最新的。后端需要配合把csrfToken写进响应里。