您好,登錄后才能下訂單哦!
這篇“Vue3中如何使用Supabase Auth方法”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Vue3中如何使用Supabase Auth方法”文章吧。
Supabase是一個自稱的 "開源Firebase替代品"。我對與Supbase合作已經有一段時間了,我想我將嘗試使用他們的認證API來為Vue.js 3應用程序進行認證設置。
首先,你為什么要使用Supabase Auth?最重要的是,如果你使用Supabase作為你的數據存儲,(它有一些非常甜蜜的好處),Supabase Auth是你可以管理對這些數據的訪問的唯一方法。其次,雖然Supabase Auth也有許多不同的功能。
沒有中間件的用戶權限(通過Postgres的行級安全)。
神奇的電子郵件鏈接
社交提供者的登錄
以及所有其他你期望的封裝在一個簡單的JavaScript SDK中的Auth功能
綜上所述,值得一提的是,Supabase Auth不是一個獨立的認證提供商,它只是為了與其他Supabase服務(數據、存儲等)一起使用。
好了,讓我們開始在我們的Vue.js 3應用程序中實施Supabase Auth。
我假設你已經有了一個用Vue Router設置的Vue.js 3應用程序,如果沒有,你可以下載這個模板代碼來進行操作。我還假設你已經有了一個Supabase賬戶和項目設置。如果沒有,你可以前往supabase.io,它將引導你完成第一步。
然后,為了與Supabase auth以及它的任何其他服務合作,我們需要安裝Supabase JavaScript SDK。
npm install @supabase/supabase-js
安裝完Supabase后,我們需要經過幾個步驟來設置它。我將創建一個名為UseSupabase.js
的組合,用來組織這個設置。
// UseSupabase.js import { createClient } from "@supabase/supabase-js"; // these can come from an environment variable if desired // not required however as they are 100% exposed on the client side anyway // and that's ok, Supabase expects this (security is provided by Row Level Security) const supabaseUrl = ""; const supabaseKey = ""; // setup client const supabase = createClient(supabaseUrl, supabaseKey); // expose supabase client export default function useSupabase() { return { supabase }; }
supabaseUrl和supabaseKey可以在Supabase儀表板上的Settings > API
。
當你在Supabase界面時,你也可以到Autentication > Settings
,設置你的網站網址,以便Supabase知道如何正確地重定向確認郵件等。它的默認值是localhost:3000,但你可以根據需要進行修改。
設置好Supabase SDK后,我們現在可以開始使用它了。首先,我將創建一個AuthUser組合,以抽象出與AuthUser的一些交互,并存留所有我們需要填寫的方法。這在我們將來想脫離Supabase時很有幫助,并幫助我們把所有的AuthUser功能集中到一個地方。
import { ref } from "vue"; // user is set outside of the useAuthUser function // so that it will act as global state and always refer to a single user const user = ref(null); export default function useAuthUser() { /** * Login with email and password */ const login = async ({ email, password }) => {}; /** * Login with google, github, etc */ const loginWithSocialProvider = (provider) => {}; /** * Logout */ const logout = async () => {}; /** * Check if the user is logged in or not */ const isLoggedIn = () => {}; /** * Register */ const register = async ({ email, password, ...meta }) => {}; /** * Update user email, password, or meta data */ const update = async (data) => {}; /** * Send user an email to reset their password * (ie. support "Forgot Password?") */ const sendPasswordRestEmail = async (email) => {}; return { user, login, loginWithSocialProvider, isLoggedIn, logout, register, update, sendPasswordRestEmail, maybeHandleEmailConfirmation, }; }
接下來,讓我們來創建典型用戶認證流程所需的頁面。我使用Tailwind CSS做了一些樣式設計,但可以根據你的需要自由調整這些樣式。
我們需要的第一個頁面是一個注冊頁面。它需要包含必要的字段,以便在Supabase中創建一個用戶。這些字段是電子郵件和密碼。我們也可以在Supabase中為我們的用戶添加任意的元數據,這意味著我們也可以讓用戶的真實姓名成為注冊的一部分。
// Register.vue <script>...</script> <template> <form class="max-w-lg m-auto" @submit.prevent="handleSubmit"> <h2 class="text-3xl mb-5">Register</h2> <label>Name <input v-model="form.name" type="text" /></label> <label>Email <input v-model="form.email" type="email" /></label> <label>Password <input v-model="form.password" type="password" /></label> <button>Register</button> </form> </template>
在腳本部分,我們可以使用一個反應式引用來跟上表單的數據,同時提供一個函數來處理表單的提交。在表單提交時,我們將從AuthUser組合中調用注冊函數(它仍然是空的,但我們將在稍后用supabase的具體調用來填充它),然后重定向到一個頁面,指示用戶檢查他們的電子郵件以確認注冊。
// Register.vue <script setup> import { ref } from "vue"; import useAuthUser from "@/composables/UseAuthUser"; import { useRouter } from "vue-router"; // Use necessary composables const router = useRouter(); const { register } = useAuthUser(); // Form reactive ref to keep up with the form data const form = ref({ name: "", email: "", password: "", }); // function to hand the form submit const handleSubmit = async () => { try { // use the register method from the AuthUser composable await register(form.value); // and redirect to a EmailConfirmation page the will instruct // the user to confirm they're email address router.push({ name: "EmailConfirmation", query: { email: form.value.email }, }); } catch (error) { alert(error.message); } }; </script> <template>...</template>
最后,我們需要為該頁面注冊路由。
// router/index.js const routes = [ //... { name: "Register", path: "/register", component: () => import("@/pages/Register.vue"), }, ]
如果你使用了模板代碼,訪問/register
,應該會得到一個看起來像這樣的頁面。
既然我們在注冊后重定向到一個EmailConfirmation頁面,我們當然需要讓它存在。它將只是一個簡單的模板和一條信息。當我們在上面重定向時,我們也提供了來自注冊表單的電子郵件作為一個查詢變量,所以我們可以在這里顯示它。
<template> <div> <h2 class="text-3xl">Thanks for registering!</h2> <p> Please confirm your email to finishing registering: {{ $route.query.email }} </p> </div> </template>
再一次,我們也需要注冊這個路由。
// router/index.js const routes = [ //... { name: "EmailConfirmation", path: "/email-confirmation", component: () => import("@/pages/EmailConfirmation.vue"), }, ]
現在訪問帶有電子郵件查詢變量的/email-confirmation
路由將看起來像這樣。
/[email protected]
在注冊并確認了他們的電子郵件后,用戶將不得不登錄。讓我們接下來創建這個頁面。
該模板將包括一個帶有電子郵件和密碼字段的表單,以及一個指向忘記密碼頁面的鏈接,還有一個處理Github登錄的鏈接。
<script>...</script> <template> <div class="max-w-lg m-auto"> <form @submit.prevent="handleLogin"> <h2 class="text-3xl mb-5">Login</h2> <label>Email <input v-model="form.email" type="email" /></label> <label>Password <input v-model="form.password" type="password" /></label> <button>Login</button> <router-link to="/forgotPassword">Forgot Password?</router-link> </form> <div class="mt-5"> <a @click.prevent="handleLogin('github')">Github</a> </div> </div> </template>
在腳本部分,我們可以創建一個反應式引用來跟上表單的值,以及一個函數來處理表單的提交。
<script setup> import { ref } from "vue"; import useAuthUser from "@/composables/UseAuthUser"; import { useRouter } from "vue-router"; // Use necessary composables const router = useRouter(); const { login, loginWithSocialProvider } = useAuthUser(); // keep up with form data const form = ref({ email: "", password: "", }); // call the proper login method from the AuthUser composable // on the submit of the form const handleLogin = async (provider) => { try { provider ? await loginWithSocialProvider(provider) : await login(form.value); router.push({ name: "Me" }); } catch (error) { alert(error.message); } }; </script> <template>...</template>
注冊完路由后,你可以訪問/login
路由,看到一個漂亮的登錄表單。
// router/index.js const routes = [ //... { name: "Login", path: "/login", component: () => import("@/pages/Login.vue"), }, ]
由于我們在上面實現了一個忘記密碼的鏈接,讓我們也把這個頁面用腳手架搭出來。
在模板中,我們只需要一個帶有單個電子郵件字段的表單,以便收集我們應該發送重置鏈接的電子郵件。
<script>...</script> <template> <form class="max-w-lg m-auto" @submit.prevent="handlePasswordReset()"> <h2 class="text-3xl mb-5">Forgot Password?</h2> <label>Email <input v-model="email" type="email" /></label> <button>Send Reset Email</button> </form> </template>
在腳本部分,我們將創建一個電子郵件反應式參考,以跟上表單中的電子郵件輸入,并定義一個函數,在表單提交時調用AuthUser可組合的sendPasswordRestEmail
函數。
<script setup> import useAuthUser from "@/composables/UseAuthUser"; import { ref } from "vue"; // use necessary composables const { sendPasswordRestEmail } = useAuthUser(); // keep up with email const email = ref(""); // function to call on submit of the form // triggers sending the reset email to the user const handlePasswordReset = async () => { await sendPasswordRestEmail(email.value); alert(`Password reset email sent to: ${email.value}`); }; </script>
最后,我們將注冊這個路由。
// router/index.js const routes = [ //... { name: "ForgotPassword", path: "/forgotPassword", component: () => import("@/pages/ForgotPassword.vue"), }, ]
現在,點擊登錄頁面上的 "忘記密碼?"鏈接將把你帶到這里。
我們需要的最后一個頁面是一個個人資料頁面,在用戶登錄后顯示他們的秘密信息。我們將它稱為/me
。
// router/index.js const routes = [ //... { name: "Me", path: "/me", component: () => import("@/pages/Me.vue"), }, ]
我們還將添加路由中間件,讓我們的程序知道這應該是一個受保護的路由,只有通過認證的用戶才能訪問。
{ name: "Me", meta: { requiresAuth: true, }, //... },
然后,為了讓這個中間件真正發揮作用,我們需要這樣來實現它。
const router = createRouter({ history: createWebHistory(), routes, }); router.beforeEach((to) => { // here we check it the user is logged in // if they aren't and the route requries auth we redirect to the login page const { isLoggedIn } = useAuthUser(); if (!isLoggedIn() && to.meta.requiresAuth) { return { name: "Login" }; } }); export default router;
頁面本身將是一個簡單的問候用戶的信息。
<script setup> import useAuthUser from "@/composables/UseAuthUser"; const { user } = useAuthUser(); </script> <template> <div v-if="user"> <!--user_metadata is the key supabase nests all arbitrary meta data under--> <div>Hello {{ user.user_metadata.name }}</div> </div> </template>
我們現在還不會嘗試查看這個頁面,因為我們還沒有實現登錄。
https://github.com/danielkellyio/supabase-auth-example
現在,頁面和AuthUser組合已經到位,我們可以開始通過調用Supabase SDK來填充AuthUser組合函數的內容。
我們需要做的第一件事是訪問我們的Supabase客戶端。我們可以通過導入UseSupabase可組合函數并從中解構Supabase客戶端來做到這一點。
import useSupabase from "@/composables/UseSupabase"; export default function useAuthUser() { const { supabase } = useSupabase(); //... }
現在我們可以通過我們的空函數,一個一個地填充它們。
為了登錄Supabase,我們需要調用supabase.auth.signIn
。我們也可以等待響應,如果有錯誤就拋出一個新的錯誤,否則就返回登錄的用戶。
const login = async ({ email, password }) => { const { user, error } = await supabase.auth.signIn({ email, password }); if (error) throw error; return user; };
loginWithSocialProvider也同樣簡單。只需要將提供者傳遞給signIn方法。
const loginWithSocialProvider = async (token) => { const { user, error } = await supabase.auth.signIn({ provider }); if (error) throw error; return user; };
現在,為了注銷,我們需要調用Supabase的signOut方法。由于用戶不再可用,所以沒有什么可以從注銷中返回。
const logout = async () => { const { error } = await supabase.auth.signOut(); if (error) throw error; };
對于isLoggedIn函數,我們只需檢查reactive ref user是否有一個值。
const isLoggedIn = () => { return !!user.value; };
如果你在想,我們在登錄用戶時從來沒有設置過這個值,你是完全正確的,但我們將利用另一個小的supabase方法來幫助我們解決這個問題,就在一分鐘之內。
register函數看起來幾乎和login函數一樣,接收電子郵件和密碼。然而,它也需要接受其他用戶信息(即元數據)。另外,我們將重定向到個人資料頁面,并附上一些查詢變量,其中包含一些有用的信息。
const register = async ({ email, password, ...meta }) => { const { user, error } = await supabase.auth.signUp( { email, password }, { //arbitrary meta data is passed as the second argument under a data key // to the Supabase signUp method data: meta, // the to redirect to after the user confirms their email // window.location wouldn't be available if we were rendering server side // but since we're all on the client it will work fine redirectTo: `${window.location.origin}/me?fromEmail=registrationConfirmation"`, } ); if (error) throw error; return user; };
請注意這個很酷的小技巧,我們把meta:...meta
。這允許我們在調用函數時,在傳遞給函數的對象中提供同一層次的元數據,但在函數中單獨訪問它。
// for example register({email: '[email protected]', password: 'password123', name: 'Daniel Kelly', favoriteFood: 'Spaghetti'}) // meta will be {name: 'Daniel Kelly', favoriteFood: 'Spaghetti'}
雖然我們實際上沒有提供更新用戶的接口,但我們可以去實現這個函數,因為Supabase讓它變得如此簡單。
const update = async (data) => { const { user, error } = await supabase.auth.update(data); if (error) throw error; return user; };
最后一個要實現的函數是sendPasswordResetEmail
。再一次,supabase有一個簡單的解決方案。
const sendPasswordRestEmail = async (email) => { const { user, error } = await supabase.auth.api.resetPasswordForEmail(email); if (error) throw error; return user; };
在這一點上,我們幾乎已經準備好開始使用我們的接口了,但還有一個關鍵步驟需要執行。我們需要知道用戶何時登錄或注銷,并相應地更新AuthUser組合中的反應式ref。
你的第一個想法可能是在登錄和注銷方法中完成這個任務,這在某些時候是可行的。然而,如果用戶因為會話過期而注銷了呢?或者如果用戶在Supabase那邊被更新或刪除了呢?在這兩種情況下,我們的登錄和注銷方法都不會被調用。
為了解決這個問題,Supabase提供了一個叫做onAuthStateChange
的函數。
我們可以在我們的supabase組合中調用這個函數,讓它監聽auth狀態的所有變化,然后相應地設置我們的用戶reactive ref。
// UseSupabase.js import { createClient } from "@supabase/supabase-js"; import useAuthUser from "@/composables/UseAuthUser"; // config const supabaseUrl = ""; const supabaseKey = ""; // setup client const supabase = createClient(supabaseUrl, supabaseKey); // ? setup auth state listener ? supabase.auth.onAuthStateChange((event, session) => { // the "event" is a string indicating what trigger the state change (ie. SIGN_IN, SIGN_OUT, etc) // the session contains info about the current session most importanly the user dat const { user } = useAuthUser(); // if the user exists in the session we're logged in // and we can set our user reactive ref user.value = session?.user || null; }); // expose supabase client export default function useSupabase() { return { supabase }; }
我選擇在UseSupabase.js中的函數調用之外做這件事,這樣它就只被調用一次,并與其他Supabase設置代碼組織在一起。
現在到了關鍵時刻。我們應該有大部分的工作。(盡管你馬上就會看到,我們還需要再做一些調整)。在你的瀏覽器中導航到注冊頁面并注冊。
之后,你應該成功地被重定向到EmailConfirmation頁面,你的電子郵件地址顯示在信息中。
另外,如果你檢查你的收件箱,你會像預期那樣收到電子郵件。
順便提一下,如果你想定制這封電子郵件的樣子,你可以在Supabase儀表板上的Authentication > Templates
。
另外,如果你在Authentication > Users
,你就可以看到你的新注冊用戶的狀態是:Waiting for Verication
!
很好,現在去點擊電子郵件中的那個鏈接吧。哦,天哪!我們被重新定向到了一個新的網站。我們被重定向到了登錄頁面......這不對。然而,請注意,標題右上方的鏈接確實寫著 "注銷"
如果我們點擊到me
頁面,它將讓我們訪問它,并正確顯示我們在注冊表格中提供的名字。
問題是,在我們點擊頁面的那一瞬間,我們的中間件正在運行,我們還沒有完全登錄,因此authStateChange還沒有發生,還沒有設置我們的用戶反應式。
讓我們在我們的中間件中做一個例外,如果查詢變量fromEmail存在,我們就繼續讓導航通過,因為我們知道,從確認郵件中來,用戶將立即登錄。
router.beforeEach((to) => { const { isLoggedIn } = useAuthUser(); if ( !isLoggedIn() && to.meta.requiresAuth && !Object.keys(to.query).includes("fromEmail") ) { return { name: "Login" }; } });
還要注意,這不是一個安全問題。如果有人在沒有登錄的情況下隨意在查詢字符串中包括fromEmail
,由于用戶不存在,反正什么都不會顯示出來,也不會從Supabase收到關于用戶的信息。
現在除了注銷鏈接外,一切都應該正常了。我們可以通過定義注銷路由并直接向其添加一個路由保護來使其工作。
{ name: "Logout", path: "/logout", beforeEnter: async () => { const { logout } = useAuthUser(); await logout(); return { name: "Home" }; }, },
注銷后,如果你愿意,你可以嘗試用不同的電子郵件再次注冊,以確認我們上面的修復對直接導航到個人資料頁面起作用。同樣,當注銷后,檢查一下登錄頁面。你應該也能用現有的用戶成功登錄!
以上就是關于“Vue3中如何使用Supabase Auth方法”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。