อยากทำให้ Supabase เข้าใจว่า ต้องใช้ Captcha Turnstile ของ Cloudflare ด้วย
เพิ่มเว็บเราเข้า Cloudflare Turnstile ก่อน
เข้าสู่ระบบของ Cloudflare แล้วไปที่เมน Turnstile หากมีเว็บของเราเพิ่มอยู่แล้วจะมีรายการแสดงขึ้นมา

หากไม่มีก็ไปกดเพิ่มก่อน โดยใส่ชื่อเว็บที่ต้องการ และ โดเมนที่เราเพิ่มไว้ใน Cloudflare

เมื่อเพิ่มเรียบร้อยเราจะได้
- Site Key: 0x4AAAAAAAKNlgbD8W2wht3r
- Secret Key: 0x4AAAAAAAKnlgMqynfdAe1heBR6oM_dJvg
เราจะเอา 2 อันนี้ไปใช้

ไปตั้งค่าที่ Supabase
เข้าสู่ระบบ Supabase ให้เรียบร้อย เข้าไปที่โครงการที่ต้องการ จากนั้นไปที่ Settings -> Auth
- ในหัวข้อ Security and Protection ให้ Enable Captcha Protection
- แล้วเลือก Captcha Providers เป็น Turnstile (Cloudflare)
- จากนั้นเอา Secret Key ที่ได้จาก Cloudflare => 0x4AAAAAAAKnlgMqynfdAe1heBR6oM_dJvg ไปใส่ในช่อง Captcha secret

ติดตั้ง Package @nuxtjs/turnstile
@nuxtjs/turnstile ด้วยคำสั่ง
npm install -D @nuxtjs/turnstile
แก้ไขไฟล์ nuxt.config.ts
- เพิ่มชื่อ @nuxtjs/turnsile เข้าไปที่ modules
- เพิ่มค่า turnstile -> siteKey ด้วย Site Key ที่เราได้มา คือ 0x4AAAAAAAKNlgbD8W2wht3r
- เพิ่มค่า runtimeConfig -> turnstile -> secretKey ด้วย Secret Key ที่เราได้มา คือ 0x4AAAAAAAKnlgMqynfdAe1heBR6oM_dJvg
/** file: nuxt.config.ts **/
export default defineNuxtConfig({
modules: ['@nuxtjs/turnstile'],
turnstile: {
siteKey: '0x4AAAAAAAKNlgbD8W2wht3r',
},
runtimeConfig: {
turnstile: {
secretKey: '0x4AAAAAAAKnlgMqynfdAe1heBR6oM_dJvg',
},
},
})
หน้าเข้าสู่ระบบ
มีการเพิ่ม <NuxtTurnstile v-model=”turnstileToken” ref=”turnstile”> เข้าไปใน form
ดูดีๆ ชื่อตัวแปรจะคล้าย ๆ กัน คือ turnstile, turnstileToken เนื่องจากหากไม่แยกมันสั่ง reset() ไม่ได้ เลยต้องทำการแยกให้ turnstile เป็น ref และ turnstileToken เป็น v-model
/** file: pages/login.vue **/
<script setup>
const supabase = await useSupabaseClient();
const user = await useSupabaseUser();
if (user.value) {
await navigateTo("/admin/dashboard", { replace: true });
}
const loading = ref(false);
const email = ref("");
const password = ref("");
const turnstile = ref();
const turnstileToken = ref();
const handleLogin = async () => {
try {
loading.value = true;
const { error } = await supabase.auth.signInWithPassword({
email: email.value,
password: password.value,
options: { captchaToken: turnstileToken.value },
});
if (error) {
return false;
}
await navigateTo("/admin/dashboard", { replace: true });
} catch (error) {
console.log(error.error_description || error.message);
} finally {
turnstile.value?.reset();
loading.value = false;
}
};
</script>
<template>
<div class="flex justify-center items-center">
<form
class="bg-yellow-500 flex flex-col gap-5 px-20 pb-20 pt-10"
@submit.prevent="handleLogin"
>
<img src="/images/logo.png" alt="KanexKane" class="w-32 mx-auto" />
<div class="join">
<Icon
name="material-symbols:person-4"
size="2em"
class="absolute ml-2 mt-2 text-base-300"
/>
<input
type="text"
placeholder="E-mail"
class="input w-full max-w-xs pl-14"
v-model="email"
autocomplete="email"
/>
</div>
<div class="join">
<Icon
name="carbon:password"
size="2em"
class="absolute ml-2 mt-2 text-base-300"
/>
<input
type="password"
placeholder="Password"
class="input w-full max-w-xs pl-14"
v-model="password"
autocomplete="current-password"
/>
</div>
<NuxtTurnstile v-model="turnstileToken" ref="turnstile" />
<button class="btn btn-primary rounded-full px-14" :disabled="loading">
{{ loading ? "Please wait..." : "Login" }}
</button>
</form>
</div>
</template>

ทำไมต้องมีการทำ turnstile.value.reset()
เพราะหากมีการเข้าสู่ระบบผิดพลาด การกดซ้ำอีกครั้งโดยไม่ทำการ reset ก่อน จะทำให้เกิดการ Error ทางฝั่ง Supabase บอกว่ามัน Duplicate ก็เลยต้องทำการ reset ทุกครั้งที่จะทำการคลิกปุ่ม Login
