Files
waf-platform/EdgeUser/web/public/js/components/common/csrf-token.js

170 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Vue.component("csrf-token", {
created: function () {
this.refreshToken()
},
mounted: function () {
let that = this
var form = this.$refs.token.form
// 监听表单提交在提交前刷新token并确保更新到 DOM
form.addEventListener("submit", function (e) {
// 如果正在刷新,等待刷新完成
if (that.refreshing) {
e.preventDefault()
e.stopPropagation()
return false
}
// 阻止默认提交,先刷新 token
e.preventDefault()
e.stopPropagation()
that.refreshing = true
// 刷新 token
that.refreshToken(function () {
// 确保 DOM 中的 token 值是最新的
that.$forceUpdate()
that.$nextTick(function () {
var tokenInput = form.querySelector('input[name="csrfToken"]')
if (tokenInput) {
tokenInput.value = that.token
}
if (that.$refs.token) {
that.$refs.token.value = that.token
}
// 确保 DOM 已更新后,再触发表单提交
setTimeout(function () {
that.refreshing = false
// 重新触发表单提交
Tea.runActionOn(form)
}, 50)
})
})
return false
})
// 自动刷新
setInterval(function () {
that.refreshToken()
}, 10 * 60 * 1000)
// 监听表单提交失败,如果是 CSRF token 错误,自动刷新 token 并重试
this.setupAutoRetry(form)
},
data: function () {
return {
token: "",
retrying: false,
refreshing: false
}
},
methods: {
refreshToken: function (callback) {
let that = this
Tea.action("/csrf/token")
.get()
.success(function (resp) {
that.token = resp.data.token
if (callback) {
callback()
}
})
.fail(function () {
if (callback) {
callback()
}
})
},
setupAutoRetry: function (form) {
let that = this
var originalFail = form.getAttribute("data-tea-fail")
// 确保 Tea.Vue 存在
if (typeof Tea === "undefined" || Tea.Vue == null) {
if (typeof Tea === "undefined") {
window.Tea = {}
}
if (Tea.Vue == null) {
Tea.Vue = {}
}
}
// 创建一个包装的 fail 函数
var wrappedFailName = "csrfAutoRetryFail_" + Math.random().toString(36).substr(2, 9)
form.setAttribute("data-tea-fail", wrappedFailName)
Tea.Vue[wrappedFailName] = function (resp) {
// 检查是否是 CSRF token 错误
var isCSRFError = false
if (resp && resp.message) {
// 检查消息是否包含 "表单已失效" 或 "001"
if (resp.message.indexOf("表单已失效") >= 0 || resp.message.indexOf("(001)") >= 0) {
isCSRFError = true
}
}
// 检查 HTTP 状态码是否为 403 或 400
if (!isCSRFError && resp && (resp.statusCode === 403 || resp.status === 403 || resp.statusCode === 400 || resp.status === 400)) {
isCSRFError = true
}
if (isCSRFError) {
// 如果不是正在重试,则立即刷新 token 并自动重试
if (!that.retrying) {
that.retrying = true
// 立即刷新 token
that.refreshToken(function () {
// 强制更新 Vue确保响应式数据已更新
that.$forceUpdate()
// 使用 $nextTick 等待 Vue 完成 DOM 更新
that.$nextTick(function () {
// 直接查找并更新 DOM 中的 input 元素(通过 name 属性)
var tokenInput = form.querySelector('input[name="csrfToken"]')
if (tokenInput) {
tokenInput.value = that.token
}
// 如果 ref 存在,也更新它
if (that.$refs.token) {
that.$refs.token.value = that.token
}
// 使用 setTimeout 确保 DOM 已完全更新
setTimeout(function () {
// 再次确认 token 值已更新
var finalTokenInput = form.querySelector('input[name="csrfToken"]')
if (finalTokenInput && finalTokenInput.value !== that.token) {
finalTokenInput.value = that.token
}
that.retrying = false
// 重新触发表单提交
Tea.runActionOn(form)
}, 150)
})
})
return // 不调用原始 fail 函数
} else {
// 如果正在重试,说明已经刷新过 token直接调用原始 fail 函数
if (originalFail && typeof Tea.Vue[originalFail] === "function") {
return Tea.Vue[originalFail].call(Tea.Vue, resp)
} else {
Tea.failResponse(resp)
}
}
}
// 不是 CSRF 错误,调用原始 fail 函数或默认处理
if (originalFail && typeof Tea.Vue[originalFail] === "function") {
return Tea.Vue[originalFail].call(Tea.Vue, resp)
} else {
Tea.failResponse(resp)
}
}
}
},
template: `<input type="hidden" name="csrfToken" :value="token" ref="token"/>`
})