简介
认证是当今网络应用的一个重要功能,但许多开发人员在设置它时遇到了困难。值得庆幸的是,现在有一些服务和库可以帮助我们卸下这个沉重的负担。
今天我们将讨论如何使用Supabase来处理Vue.js应用程序中的用户认证。Supabase将作为应用程序中认证的后端,具有登录和注册功能,同时还有一个只能用有效凭证访问的私人路线。
什么是Supabase?
Supabase通常被描述为Firebase的一个开源替代品。它提供了Firebase的一些关键功能,其中之一包括用户认证和管理。
Supabase提供了对不同的外部认证提供者的支持,如密码、电话号码,以及谷歌、Twitter、Facebook和Github等身份供应商。
设置Vue.js
为了开始工作,我们将使用Vue CLI来快速搭建一个新项目的支架。CLI可以通过运行以下命令进行全局安装。
npm install -g @vue/cli
# OR
yarn global add @vue/cli
接下来,运行下面的命令来创建一个Vue项目。
vue create supabase-auth
你会被提示选择一个预设;选择手动选择功能的选项。
之后,选择Router和Vuex并点击回车,然后选择Vue 3.x版本,因为我们将使用新的组合API。最后,在所有其他选择上点击回车,让你的Vue应用准备好。
设置Supabase
要想开始,首先你要通过访问Supabase的登录页面创建一个账户,并继续使用你的Github账户进行登录。
登录到仪表板后,点击新项目按钮,创建你的第一个项目。你应该看到弹出以下模式。
为你的项目选择一个名称,一个数据库密码,以及一个离你很近的地区。该项目需要一些时间才能完全创建。
完成后,进入**设置,**然后是API,并复制URL和匿名公共API密钥。
在你的项目根部创建一个.env.local 文件,并将凭证保存在其中,就这样。
VUE_APP_SUPABASE_URL=YOUR_SUPABSE_URL
VUE_APP_SUPABASE_PUBLIC_KEY=YOUR_SUPABSE_PUBLIC_KEY
设置Supabase客户端库
运行下面的命令来安装Supabase客户端库。
yarn add @supabase/supabase-js
接下来我们要初始化Supabase,在我们的src 目录中创建一个supabase.js 文件并粘贴以下代码。
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.VUE_APP_SUPABASE_URL
const supabaseAnonKey = process.env.VUE_APP_SUPABASE_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
创建我们的页面
现在让我们创建一些Vue组件页面来处理我们项目的注册和登录功能,以及一个仪表盘页面。
在本教程中,我们将不对我们的应用程序进行样式设计,以避免混淆我们的HTML标记,但你总是可以选择你喜欢的样式。
这里是我们的SignIn 页面的标记。
<!-- src/views/SignIn.vue -->
<template>
<div>
<h1>Login Page</h1>
<form @submit.prevent="signIn">
<input
class="inputField"
type="email"
placeholder="Your email"
v-model="form.email"
/>
<input
class="inputField"
type="password"
placeholder="Your Password"
v-model="form.password"
/>
<button type="submit">Sign In</button>
</form>
<p>
Don't have an account?
<router-link to="/sign-up">Sign Up</router-link>
</p>
</div>
</template>
现在让我们为我们的SignUp 页面做标记。
<!-- src/views/SignUp.vue -->
<template>
<div>
<h1>SignUp Page</h1>
<form @submit.prevent="signUp">
<input
class="inputField"
type="email"
placeholder="Your email"
v-model="form.email"
/>
<input
class="inputField"
type="password"
placeholder="Your Password"
v-model="form.password"
/>
<button type="submit">Sign Up</button>
</form>
<p>
Already have an account?
<router-link to="/sign-in">Log in</router-link>
</p>
</div>
</template>
最后,我们的Dashboard 页面。
<!-- src/views/Dashboard.vue -->
<template>
<div>
<h1>Welcome to our Dashboard Page</h1>
<button @click.prevent="signOut">Sign out</button>
<p>Welcome: {{ userEmail }}</p>
</div>
</template>
用Vue Router设置路由
现在我们已经创建了我们的页面,我们需要设置路由,以便我们可以在它们之间移动。为此,我们将使用Vue Router。
让我们在路由器文件中为我们的不同页面声明路由,就像这样。
// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
function loadPage(view) {
return () =>
import(
/* webpackChunkName: "view-[request]" */ `@/views/${view}.vue`
);
}
const routes = [
{
path: '/',
name: 'Dashboard',
component: loadPage("Dashboard"),
meta: {
requiresAuth: true,
}
},
{
path: '/sign-up',
name: 'SignUp',
component: loadPage("SignUp")
},
{
path: '/sign-in',
name: 'SignIn',
component: loadPage("SignIn")
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
router.beforeEach((to, from, next) => {
// get current user info
const currentUser = supabase.auth.user();
const requiresAuth = to.matched.some
(record => record.meta.requiresAuth);
if(requiresAuth && !currentUser) next('sign-in');
else if(!requiresAuth && currentUser) next("/");
else next();
})
export default router
我们第一个路由中的meta 对象是用来保存该路由的额外信息的。它有一个名为requiresAuth 的属性,这个属性被设置为true ,我们要用这个属性来防范这个路由的未经认证的用户。
从第34-42行,我们正在设置所谓的 "导航卫士"。
代码中发生的事情是进行检查,以确定某个路由是否需要认证,以及是否有用户当前正在登录。如果该路线需要认证,但没有人登录,用户将被重定向到sign-in 。但如果该路由需要认证,并且有一个用户登录,那么用户就会被重定向到仪表板的私人路由。
设置Vuex
Vuex是Vue应用程序中的一个工具,用于存储我们应用程序中所有组件可访问的数据。它有自己的一套规则,确保存储的数据可以被相应地改变和更新。
我们将在Vuex中存储我们组件的所有逻辑。
使用Vuex的一个注意事项是,一旦页面被重新加载,所有存储的数据都会被重置。为了解决这个问题,我们将使用vuex-persistedstate。这个包可以帮助保存存储在Vuex中的数据,即使在页面重新加载之后。
在你的终端输入以下内容来安装vuex-persistedstate。
yarn add vuex-persistedstate
#OR
npm install --save vuex-persistedstate
配置我们的Vuex商店
这里,我们正在配置vuex-persistedstate ,然后导入Supabase和Vue Router。我们将需要它们来创建我们的Vuex商店动作。
import { createStore } from 'vuex'
import createPersistedState from "vuex-persistedstate";
import router from '../router';
import { supabase } from "../supabase";
// Create store
export default createStore({
state:{},
mutations:{},
actions:{},
plugins: [createPersistedState()]
});
将数据存储在State
我们的Vuex商店中的state 对象是实际存储数据的。在这里我们可以定义我们的数据的默认值。
state: {
user:null
};
在我们的state 对象中,我们将user 的默认值设置为null ,因为这是在用户没有登录到我们的应用程序时的值。
用突变来改变状态
突变是我们改变Vuex存储中state 对象的唯一方法。
一个突变接受state 和一个来自提交行动的值,就像这样。
mutations: {
setUser(state, payload) {
state.user = payload;
},
},
当这个突变被提交时,它将我们的user 状态的默认值改为传递给它的任何值。
使用Actions 来提交突变
actions 对象包含了可以用来提交突变的函数,以改变我们应用程序中的状态。动作也可以调度其他动作。对于我们的示例应用程序,我们将使用三个不同的动作:注册、登录和退出。
签到动作
我们的signUpAction 动作接收表单数据,然后调用Supabase的注册功能。这个函数接收收集到的表单数据,对其进行验证,并在所有要求都满足的情况下创建一个新用户。
async signUpAction({dispatch}, form) {
try {
const { error } = await supabase.auth.signUp({
email: form.email,
password: form.password,
});
if (error) throw error;
alert("You've been registered successfully");
await dispatch("signInAction", form)
} catch (error) {
alert(error.error_description || error.message);
}
},
一旦用户被创建,就会弹出一个带有成功信息的警告,然后派发signInAction 动作。singInAction 接受我们的表单数据,并记录我们新注册的用户,这样他们就可以访问私人仪表板路线。如果在任何时候失败,就会弹出一个错误警报。
登录动作
signInAction 动作也接收了用户填写的表单数据。它将这些数据传递给我们的SupabasesignIn 函数,该函数根据我们的用户表验证这些数据,以检查这些用户是否存在。如果是的话,用户就会被登录并被重定向到私人仪表板路线。
接下来,我们提交setUser 突变,它将我们的user 状态的值设置为当前登录的用户的电子邮件。
async signInAction({ commit }, form) {
try {
const { error, user } = await supabase.auth.signIn({
email: form.email,
password: form.password,
});
if (error) throw error;
alert("You've Signed In successfully");
await router.push('/')
commit('setUser', user.email)
} catch (error) {
alert(error.error_description || error.message);
}
},
签出动作
我们的signOutAction 动作调用了SupabasesignOut 函数,将我们的user 状态的值重设为空,然后将用户重定向到登录页面。
async signOutAction({ commit }) {
try {
const { error } = await supabase.auth.signOut();
if (error) throw error;
commit('setUser', null)
alert("You've been logged Out successfully");
await router.push("/sign-in");
} catch (error) {
alert(error.error_description || error.message);
}
},
最后,这就是你的Vuex商店应该有的样子。
// src/store/index.js
import { createStore } from 'vuex'
import createPersistedState from "vuex-persistedstate";
import router from '../router';
import { supabase } from "../supabase";
export default createStore({
state: {
user: null,
},
mutations: {
setUser(state, payload) {
state.user = payload;
},
},
actions: {
async signInAction({ commit }, form) {
try {
const { error, user } = await supabase.auth.signIn({
email: form.email,
password: form.password,
});
if (error) throw error;
alert("You've Signed In successfully");
await router.push('/')
commit('setUser', user.email)
} catch (error) {
alert(error.error_description || error.message);
}
},
async signUpAction({dispatch}, form) {
try {
const { error} = await supabase.auth.signUp({
email: form.email,
password: form.password,
});
if (error) throw error;
alert("You've been registered successfully");
await dispatch("signInAction", form)
} catch (error) {
alert(error.error_description || error.message);
}
},
async signOutAction({ commit }) {
try {
const { error } = await supabase.auth.signOut();
if (error) throw error;
commit('setUser', null)
alert("You've been logged Out successfully");
await router.push("/sign-in");
} catch (error) {
alert(error.error_description || error.message);
}
},
},
modules: {
},
plugins: [createPersistedState()],
})
为组件添加逻辑
现在是时候让我们倒退一下,通过添加一些逻辑使我们之前创建的组件完全发挥作用。
让我们从我们的SignUp 组件开始。
<!-- src/views/SignUp.vue -->
<template>
<div>
<!-- Our markup goes here -->
</div>
</template>
<script>
import { reactive } from "vue";
import { useStore } from "vuex";
export default {
setup() {
// wrap data gotten from form input in vue's reactive object
const form = reactive({
email: "",
password: "",
});
//create new store instance
const store = useStore();
const signUp = () => {
// dispatch the signup action to register new user
store.dispatch("signUpAction", form);
};
return {
form,
signUp,
};
},
};
</script>
现在,让我们为我们的SignIn 组件添加逻辑。SignIn 和SignUp 组件是相似的;唯一的区别是调用signIn 函数而不是signUp 函数。
<!-- src/views/SignIn.vue -->
<template>
<div>
<!-- Our markup goes here -->
</div>
</template>
<script>
import { reactive } from "vue";
import { useStore } from "vuex";
export default {
setup() {
// wrap data gotten from form input in vue's reactive object
const form = reactive({
email: "",
password: "",
});
//create new store instance
const store = useStore();
const signUp = () => {
// dispatch the sign in action to Log in the user
store.dispatch("signInAction", form);
};
return {
form,
signIn,
};
},
};
</script>
让我们也给Dashboard 组件添加逻辑,这样我们的登录用户就可以在他们想登录的时候退出。
<!-- src/views/Dashboard.vue -->
<template>
<div>
<h1>Welcome to our Dashboard Page</h1>
<button @click.prevent="signOut">Sign out</button>
<p>Welocome: {{ userEmail }}</p>
</div>
</template>
<script>
import { useStore } from "vuex";
import { computed } from "vue";
export default {
setup() {
//create store instance
const store = useStore();
// Fetches email of logged in user from state
const userEmail = computed(() => store.state.user);
const signOut = () => {
// dispatch the sign out action to log user out
store.dispatch("signOutAction");
};
return {
signOut,
userEmail,
};
},
};
</script>
这样就完成了我们需要的所有逻辑,使我们的组件开始运行。
总结
在本教程中,我们回顾了如何使用Supabase和Vue进行用户认证。我们还学习了如何在我们的Vue应用中使用Vuex和Vue Router以及新的组合API。
如果你想打好基础,本教程的完整源代码可以在这里找到。
The post Theultimate guide to authentication in Vue.js with Supabaseappeared first onLogRocket Blog.