mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-18 13:54:46 +08:00
fix(auth): add submit Turnstile widget in email verify flow
- 邮箱验证码流程中,提交注册前要求重新完成 Turnstile 验证 - 修复发送验证码后 token 被清空导致注册时缺少 turnstile_token 的问题 - submit/resend 两个 widget 通过 showResendTurnstile 互斥显示
This commit is contained in:
@@ -113,8 +113,7 @@ func (h *AuthHandler) Register(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turnstile 验证 — 始终执行,防止绕过
|
// Turnstile 验证 — 始终执行,防止机器人自动化注册
|
||||||
// TODO: 确认前端在提交邮箱验证码注册时也传递了 turnstile_token
|
|
||||||
if err := h.authService.VerifyTurnstile(c.Request.Context(), req.TurnstileToken, ip.GetClientIP(c)); err != nil {
|
if err := h.authService.VerifyTurnstile(c.Request.Context(), req.TurnstileToken, ip.GetClientIP(c)); err != nil {
|
||||||
response.ErrorFrom(c, err)
|
response.ErrorFrom(c, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -69,6 +69,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Turnstile Widget for Submit -->
|
||||||
|
<div v-if="turnstileEnabled && turnstileSiteKey && !showResendTurnstile">
|
||||||
|
<TurnstileWidget
|
||||||
|
ref="submitTurnstileRef"
|
||||||
|
:site-key="turnstileSiteKey"
|
||||||
|
@verify="onSubmitTurnstileVerify"
|
||||||
|
@expire="onSubmitTurnstileExpire"
|
||||||
|
@error="onSubmitTurnstileError"
|
||||||
|
/>
|
||||||
|
<p v-if="errors.submitTurnstile" class="input-error-text mt-2 text-center">
|
||||||
|
{{ errors.submitTurnstile }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Turnstile Widget for Resend -->
|
<!-- Turnstile Widget for Resend -->
|
||||||
<div v-if="turnstileEnabled && turnstileSiteKey && showResendTurnstile">
|
<div v-if="turnstileEnabled && turnstileSiteKey && showResendTurnstile">
|
||||||
<TurnstileWidget
|
<TurnstileWidget
|
||||||
@@ -101,7 +115,7 @@
|
|||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<!-- Submit Button -->
|
<!-- Submit Button -->
|
||||||
<button type="submit" :disabled="isLoading || !verifyCode" class="btn btn-primary w-full">
|
<button type="submit" :disabled="isLoading || !verifyCode || (turnstileEnabled && !submitTurnstileToken)" class="btn btn-primary w-full">
|
||||||
<svg
|
<svg
|
||||||
v-if="isLoading"
|
v-if="isLoading"
|
||||||
class="-ml-1 mr-2 h-4 w-4 animate-spin text-white"
|
class="-ml-1 mr-2 h-4 w-4 animate-spin text-white"
|
||||||
@@ -209,6 +223,10 @@ const turnstileEnabled = ref<boolean>(false)
|
|||||||
const turnstileSiteKey = ref<string>('')
|
const turnstileSiteKey = ref<string>('')
|
||||||
const siteName = ref<string>('Sub2API')
|
const siteName = ref<string>('Sub2API')
|
||||||
|
|
||||||
|
// Turnstile for submit
|
||||||
|
const submitTurnstileRef = ref<InstanceType<typeof TurnstileWidget> | null>(null)
|
||||||
|
const submitTurnstileToken = ref<string>('')
|
||||||
|
|
||||||
// Turnstile for resend
|
// Turnstile for resend
|
||||||
const turnstileRef = ref<InstanceType<typeof TurnstileWidget> | null>(null)
|
const turnstileRef = ref<InstanceType<typeof TurnstileWidget> | null>(null)
|
||||||
const resendTurnstileToken = ref<string>('')
|
const resendTurnstileToken = ref<string>('')
|
||||||
@@ -216,7 +234,8 @@ const showResendTurnstile = ref<boolean>(false)
|
|||||||
|
|
||||||
const errors = ref({
|
const errors = ref({
|
||||||
code: '',
|
code: '',
|
||||||
turnstile: ''
|
turnstile: '',
|
||||||
|
submitTurnstile: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
// ==================== Lifecycle ====================
|
// ==================== Lifecycle ====================
|
||||||
@@ -284,6 +303,21 @@ function startCountdown(seconds: number): void {
|
|||||||
|
|
||||||
// ==================== Turnstile Handlers ====================
|
// ==================== Turnstile Handlers ====================
|
||||||
|
|
||||||
|
function onSubmitTurnstileVerify(token: string): void {
|
||||||
|
submitTurnstileToken.value = token
|
||||||
|
errors.value.submitTurnstile = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubmitTurnstileExpire(): void {
|
||||||
|
submitTurnstileToken.value = ''
|
||||||
|
errors.value.submitTurnstile = 'Verification expired, please try again'
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubmitTurnstileError(): void {
|
||||||
|
submitTurnstileToken.value = ''
|
||||||
|
errors.value.submitTurnstile = 'Verification failed, please try again'
|
||||||
|
}
|
||||||
|
|
||||||
function onTurnstileVerify(token: string): void {
|
function onTurnstileVerify(token: string): void {
|
||||||
resendTurnstileToken.value = token
|
resendTurnstileToken.value = token
|
||||||
errors.value.turnstile = ''
|
errors.value.turnstile = ''
|
||||||
@@ -385,7 +419,7 @@ async function handleVerify(): Promise<void> {
|
|||||||
email: email.value,
|
email: email.value,
|
||||||
password: password.value,
|
password: password.value,
|
||||||
verify_code: verifyCode.value.trim(),
|
verify_code: verifyCode.value.trim(),
|
||||||
turnstile_token: initialTurnstileToken.value || undefined,
|
turnstile_token: submitTurnstileToken.value || undefined,
|
||||||
promo_code: promoCode.value || undefined,
|
promo_code: promoCode.value || undefined,
|
||||||
invitation_code: invitationCode.value || undefined
|
invitation_code: invitationCode.value || undefined
|
||||||
})
|
})
|
||||||
@@ -399,6 +433,12 @@ async function handleVerify(): Promise<void> {
|
|||||||
// Redirect to dashboard
|
// Redirect to dashboard
|
||||||
await router.push('/dashboard')
|
await router.push('/dashboard')
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
// Reset submit turnstile on error
|
||||||
|
if (submitTurnstileRef.value) {
|
||||||
|
submitTurnstileRef.value.reset()
|
||||||
|
submitTurnstileToken.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
const err = error as { message?: string; response?: { data?: { detail?: string } } }
|
const err = error as { message?: string; response?: { data?: { detail?: string } } }
|
||||||
|
|
||||||
if (err.response?.data?.detail) {
|
if (err.response?.data?.detail) {
|
||||||
|
|||||||
Reference in New Issue
Block a user