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。
安装Supabase
我假设你已经有了一个用Vue Router设置的Vue.js 3应用程序,如果没有,你可以下载这个模板代码来进行操作。我还假设你已经有了一个Supabase账户和项目设置。如果你还没有,可以访问supabase.io,该网站会引导你完成第一步。
然后,为了与Supabase auth以及它的任何其他服务合作,我们需要安装Supabase JavaScript SDK。
npm install @supabase/supabase-js
设置Supabase
安装完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,但你可以根据需要进行修改。
创建一个AuthUser组合
设置好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进行样式设计,不过这些样式可以根据你的需求进行自由调整。
注册.vue
我们需要的第一个页面是一个注册页面。它需要包含必要的字段,以便在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.vue
既然我们要重定向到一个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]
登录.vu
在注册并确认了他们的电子邮件后,用户将不得不登录。让我们接下来创建这个页面。
该模板将包括一个带有电子邮件和密码字段的表单,以及一个指向忘记密码页面的链接,还有一个处理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"), }, ]
ForgotPassword.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.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(); //... }
现在我们可以通过我们的空函数,一个一个地填充它们。
login()
为了登录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()
loginWithSocialProvider也同样简单。只需要将提供者传递给signIn方法。
const loginWithSocialProvider = async (token) => { const { user, error } = await supabase.auth.signIn({ provider }); if (error) throw error; return user; };
logout()
要注销当前用户,我们需使用Supabase的signOut方法。由于用户不再可用,所以没有什么可以从注销中返回。
const logout = async () => { const { error } = await supabase.auth.signOut(); if (error) throw error; };
isLoggedIn()
对于isLoggedIn函数,我们只需检查reactive ref user是否有一个值。
const isLoggedIn = () => { return !!user.value; };
如果你在想,我们在登录用户时从来没有设置过这个值,你是完全正确的,但我们将利用另一个小的supabase方法来帮助我们解决这个问题,就在一分钟之内。
register()
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'}
update()
尽管我们没有提供更新用户接口,但是通过Supabase,我们可以轻松实现这个函数。
const update = async (data) => { const { user, error } = await supabase.auth.update(data); if (error) throw error; return user; };
sendPasswordResetEmail()
最后一个要实现的函数是sendPasswordResetEmail
。再一次,supabase有一个简单的解决方案。
const sendPasswordRestEmail = async (email) => { const { user, error } = await supabase.auth.api.resetPasswordForEmail(email); if (error) throw error; return user; };
观察Auth状态的变化
我们已经接近开始使用接口的阶段,但还需完成一个关键步骤。我们需要知道用户何时登录或注销,并相应地更新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方法的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

vue3+vite:src使用require动态导入图片报错和解决方法vue3+vite动态的导入多张图片vue3如果使用的是typescript开发,就会出现require引入图片报错,requireisnotdefined不能像使用vue2这样imgUrl:require(’…/assets/test.png’)导入,是因为typescript不支持require所以用import导入,下面介绍如何解决:使用awaitimport

tinymce是一个功能齐全的富文本编辑器插件,但在vue中引入tinymce并不像别的Vue富文本插件一样那么顺利,tinymce本身并不适配Vue,还需要引入@tinymce/tinymce-vue,并且它是国外的富文本插件,没有通过中文版本,需要在其官网下载翻译包(可能需要翻墙)。1、安装相关依赖npminstalltinymce-Snpminstall@tinymce/tinymce-vue-S2、下载中文包3.引入皮肤和汉化包在项目public文件夹下新建tinymce文件夹,将下载的

想要实现页面的局部刷新,我们只需要实现局部组件(dom)的重新渲染。在Vue中,想要实现这一效果最简便的方式方法就是使用v-if指令。在Vue2中我们除了使用v-if指令让局部dom的重新渲染,也可以新建一个空白组件,需要刷新局部页面时跳转至这个空白组件页面,然后在空白组件内的beforeRouteEnter守卫中又跳转回原来的页面。如下图所示,如何在Vue3.X中实现点击刷新按钮实现红框范围内的dom重新加载,并展示对应的加载状态。由于Vue3.X中scriptsetup语法中组件内守卫只有o

Vue实现博客前端,需要实现markdown的解析,如果有代码则需要实现代码的高亮。Vue的markdown解析库有很多,如markdown-it、vue-markdown-loader、marked、vue-markdown等。这些库都大同小异。这里选用的是marked,代码高亮的库选用的是highlight.js。具体实现步骤如下:一、安装依赖库在vue项目下打开命令窗口,并输入以下命令npminstallmarked-save//marked用于将markdown转换成htmlnpmins

最终效果安装VueCropper组件yarnaddvue-cropper@next上面的安装值针对Vue3的,如果时Vue2或者想使用其他的方式引用,请访问它的npm官方地址:官方教程。在组件中引用使用时也很简单,只需要引入对应的组件和它的样式文件,我这里没有在全局引用,只在我的组件文件中引入import{userInfoByRequest}from'../js/api'import{VueCropper}from'vue-cropper&

vue3+ts+axios+pinia实现无感刷新1.先在项目中下载aiXos和pinianpmipinia--savenpminstallaxios--save2.封装axios请求-----下载js-cookienpmiJS-cookie-s//引入aixosimporttype{AxiosRequestConfig,AxiosResponse}from"axios";importaxiosfrom'axios';import{ElMess

前言无论是vue还是react,当遇到多处重复代码的时候,我们都会想着如何复用这些代码,而不是一个文件里充斥着一堆冗余代码。实际上,vue和react都可以通过抽组件的方式来达到复用,但如果遇到一些很小的代码片段,你又不想抽到另外一个文件的情况下,相比而言,react可以在相同文件里面声明对应的小组件,或者通过renderfunction来实现,如:constDemo:FC=({msg})=>{returndemomsgis{msg}}constApp:FC=()=>{return(

使用Vue构建自定义元素WebComponents是一组web原生API的统称,允许开发者创建可复用的自定义元素(customelements)。自定义元素的主要好处是,它们可以在使用任何框架,甚至是在不使用框架的场景下使用。当你面向的最终用户可能使用了不同的前端技术栈,或是当你希望将最终的应用与它使用的组件实现细节解耦时,它们会是理想的选择。Vue和WebComponents是互补的技术,Vue为使用和创建自定义元素提供了出色的支持。你可以将自定义元素集成到现有的Vue应用中,或使用Vue来构
