affiliate-dash 绑定 UID 强制校验:绑定账号与第一步填写 UID 不一致时禁止提交

- bind 时记录 expectedGameAccount(第一步 UID 权威值)
- 轮询 bind-result 时本地对比 boundAccount 与 expectedGameAccount(去空白),不依赖平台 mismatch 字段
- submit 前实时拉 bind-result 二次校验,不一致 409 拒绝(前端无法绕过)
- 前端:bindMismatch 时不显示提交发货按钮,提示核对后重新绑定
- 拉取失败不阻塞轮询与提交(平台侧提交仍会校验)
This commit is contained in:
yml2213
2026-08-05 20:39:13 +08:00
parent f455f853b1
commit 0933b4514f
2 changed files with 50 additions and 2 deletions
@@ -415,6 +415,31 @@ export async function submitAffiliateDashClaim(
const now = nowIso()
const isMock = Boolean(flow.mock?.enabled)
// 强制校验:绑定返回的游戏账号与第一步填写 UID 不一致时禁止提交(防止 uid 输错),
// 不依赖平台 mismatch 字段。拉取绑定结果失败时不阻塞(平台提交时仍会校验)。
if (!isMock && flow.bindUuid) {
let mismatch = false
try {
const bindResult = await getAffiliateDashBindResult({
orderNo: flow.orderNo,
bindUuid,
})
const boundAccount = bindResult.gameAccount
mismatch =
Boolean(bindResult.mismatch) ||
Boolean(boundAccount && normalizeUid(boundAccount) !== normalizeUid(gameAccount))
} catch {
// 拉取失败:保持放行
}
if (mismatch) {
throw createHttpError('绑定账号与填写 UID 不一致,请确认后重新绑定', {
statusCode: 409,
errorCode: 'affiliate_dash_bind_mismatch',
})
}
}
const result = isMock
? {
status: 'delivered',
@@ -490,6 +515,7 @@ async function bindAffiliateDashClaimForTask(task: TaskRow, gameAccount: string)
bindUrl: bindResult.bindUrl,
qrUrl: bindResult.qrUrl,
gameAccount,
expectedGameAccount: gameAccount,
}
const updatedTask = await updateTask(task.id, {
@@ -534,12 +560,20 @@ async function refreshAffiliateDashBindState(task: TaskRow): Promise<TaskRow | n
orderNo: flow.orderNo,
bindUuid: flow.bindUuid,
})
const boundAccount = result.gameAccount || flow.boundAccount
// 本地强制校验:绑定返回的游戏账号与第一步填写的 UID 不一致时置 mismatch
// (不依赖平台 mismatch 字段,防止平台未标记但实际账号不一致的情况)。
const localMismatch = Boolean(
boundAccount &&
flow.expectedGameAccount &&
normalizeUid(boundAccount) !== normalizeUid(flow.expectedGameAccount),
)
const nextFlow = {
...flow,
bound: result.bound,
boundAccount: result.gameAccount || flow.boundAccount,
boundAccount,
gameChannel: result.gameChannel || flow.gameChannel,
bindMismatch: result.mismatch,
bindMismatch: Boolean(result.mismatch) || localMismatch,
}
const now = nowIso()
@@ -558,6 +592,12 @@ async function refreshAffiliateDashBindState(task: TaskRow): Promise<TaskRow | n
}
}
function normalizeUid(value: unknown) {
return String(value || '')
.trim()
.replace(/\s+/g, '')
}
export async function rebindKuaishouCloudClaimRole(token: unknown) {
const context = await getClaimContext(token)
assertLewanClaimTask(context.task)