[Nuxt 3] Supabase + Cloudflare Turnstile


อยากทำให้ 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

0 0 votes
Article Rating
เราใช้คุกกี้เพื่อให้ทุกคนได้รับประสบการณ์การใช้งานที่ดียิ่งขึ้น
0
Would love your thoughts, please comment.x
()
x