如何在Vue.js和Firebase应用程序中管理用户状态

440 阅读8分钟

在Vue.js和Firebase应用程序中管理用户状态

在这篇文章中,我们将讨论如何使用Vuex 4和Vue 3.0中的Composition API来建立一个状态管理系统,用Firebase Auth来验证用户。

这些组件将帮助我们拥有一个全局状态,我们可以从Vue.js应用程序的任何地方访问。

先决条件

要跟上,你需要。

  • 对Vue.js和Composition API有一个基本的了解。
  • 熟悉Firebase第9版
  • 在你的本地机器上安装Node.js
  • 一个网络浏览器。

目标

  • 使用Vuex 4和Composition API。
  • 在Vue.js应用程序中管理用户状态。
  • 在Vue.js中整合Firebase。

入门

要创建一个Vue.js应用程序,你需要有Vue CLI。要安装它,请在你的终端运行以下命令。

npm install -g @vue/cli

安装完成后,继续用下面的命令创建一个Vue应用程序。

vue create firebase-vue-user-management

在这个屏幕上,选择Vue 3

preset

最后在这个屏幕上选择Use NPM

package manager

上述配置将创建一个以npm为包管理器的Vue 3应用程序。

现在,运行以下命令来安装我们将在项目中使用的依赖项。

npm install vue-router@4

npm install vuex@next --save
  • vue-router@4 - 要在Vue应用程序中设置路由。
  • vuex@next - 用于状态管理。

设置Firebase Auth

要创建一个新的Firebase项目,请在顶部导航栏中选择Go to console

在这里,点击Add new project ,将项目命名为vue-firebase-auth

New Project

你会被重定向到项目的仪表板。在仪表板上,点击网络图标来注册你的前端应用程序。

Dashboard

将你的应用程序命名为vuex-firebase-authentication ,并点击Register app

复制Firebase提供的配置,然后点击Continue to console

回到仪表板上,点击左侧边栏的Authentication

Authentication

最后,启用Email/Passwordsave

将Firebase添加到Vue.js应用程序中

打开终端,输入以下命令来安装Firebase。

npm install firebase

安装完成后,在src 文件夹中创建一个新的文件夹,命名为firebase

在这个文件夹中,创建一个config.js 文件。用以下代码修改该文件。

//Import the required methods
import { initializeApp } from 'firebase/app'
import { getAuth } from 'firebase/auth'

//The config we copied from firebase(Replace with your config)
const firebaseConfig = {
    apiKey: "",
    authDomain: "",
    projectId: "",
    storageBucket: "",
    messagingSenderId: "",
    appId: ""
  };

//initialize the firebase app
initializeApp(firebaseConfig)

//initialize firebase auth
const auth = getAuth()

//export the auth object
export { auth }

在上面的代码中,我们已经。

  • 从Firebase导入了所需的函数。我们将使用initializaApp() 来创建一个Firebase应用实例,使用getAuth() 来创建一个Firebase Auth对象。

  • 我们还使用了Firebase平台的配置文件,然后调用了initializeApp() 方法,并将firebaseConfig 作为参数传入。

  • 最后,我们使用getAuth() 方法创建了一个auth 对象。

创建一个商店

我们现在需要创建一个全局存储来帮助进行状态管理。这将使我们能够从任何组件中访问和改变用户的状态。

要做到这一点,在src 目录下创建一个文件夹store 。在这个store 文件夹中,创建一个index.js 文件并粘贴以下代码。

import { createStore } from 'vuex'

//Firebase imports
import { auth } from '../firebase/config'
import {
    createUserWithEmailAndPassword,
    signInWithEmailAndPassword,
    signOut
} from 'firebase/auth'

const store = createStore({
    state: {
        //The user state will initially be null. After login, this state will be updated
        user: null
    },
    mutations: {
        //Mutation to update the user state
        //Takes in two arguments, the state and the payload. When we call this mutation, the payload will be user object from firebase auth
        //When the user logs out, we call the mutation and the payload will be null
        setUser(state, payload) {
            state.user = payload
            //Log out the user state
            console.log(state.user)
        }
    },
    actions: {
        async signup(context, { email, password }){
            const response = await createUserWithEmailAndPassword(auth, email, password)
            if (response) {
                context.commit('setUser', response.user)
            } else {
                throw new Error('signup failed')
            }
        },

        async login(context, { email, password }){
            const response = await signInWithEmailAndPassword(auth, email, password)
            if (response) {
                context.commit('setUser', response.user)
            } else {
                throw new Error('login failed')
            }
        },

        async logout(context){
            await signOut(auth)

            context.commit('setUser', null)
        }
    }
})

// export the store
export default store

在上面的代码中,我们有。

  • vuex 中导入createStore() ,这将我们创建一个全局存储。

  • 从Firebase文件夹中导入了auth 对象。

  • 导入了3个方法。

    • createUserWithEmailAndPassword() 帮助创建一个带有电子邮件和密码的用户账户。
    • signInWithEmailAndPassword() 允许用户用电子邮件和密码登录。
    • signOut() 注销一个用户。

我们还使用createStore() 方法创建了一个全局存储,并传入一个包含statemutationsactions 的对象。

state mutations 用于突变/更新 。 提交 ,然后更新 。state actions mutations state

state 里面,我们有user 状态,最初是空的。当用户登录时,这部分状态将被更新。

setUser() 突变是用来更新user 状态的。它接收两个参数,statepayload 。这个突变在每次用户登录、注册或注销时都会提交。

当用户注册或登录时,payload 将是Firebase发回的用户对象,作为一个响应。当用户签出时,有效载荷将为空。

还有三个动作将从不同的页面被派发。

signup()动作接收了emailpassword ,这两个数据将从派发动作的页面中传递出来。

这个动作使用signInWithEmailAndPassword() 方法向Firebase发送一个请求,并将auth,email, 和password 作为参数进行解析。

Firebase以对象的形式发回一个响应,它被存储在constresponse

如果有来自Firebase的响应,setUser() 的突变被提交,response.user 作为有效载荷被传递。否则就会抛出一个错误。

login()动作使用的逻辑与signup() 动作相同。

logout()动作使用signOut() 方法,该方法接收auth 对象作为唯一参数。然后,它提交了setUser() 突变,并将null 作为有效载荷。

创建页面

我们将用Tailwind CSS来设计我们的项目。要了解你如何用Vue设置Tailwind,请点击这里

在你用Vue.js设置了Tailwind之后,你可能会遇到这样的错误:Error: PostCSS plugin tailwindcss requires PostCSS 8 。为了纠正这个错误,请运行这些命令。

npm uninstall tailwindcss postcss autoprefixer

npm install tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9

npm run serve

现在,在src/components 文件夹中,创建一个名为Navbar.vue 的文件,并粘贴以下代码。

<template>
  <nav class="flex items-center justify-between">
    <h1 class="text-2xl">Firebase Vuex Auth</h1>

    <!-- for all users -->
    <div class="">
      <router-link to="/">Home</router-link>
    </div>

    <!-- for logged in users -->
    <div class="flex space-x-4">
      <button>Logout</button>
    </div>

    <!-- for logged out users -->
    <div class="flex space-x-4">
      <router-link to="/login">Login</router-link>
      <router-link to="/signup">Signup</router-link>
    </div>
  </nav>
</template>

<script>
export default {

}
</script>

在上面的代码中,我们已经创建了一个基本的导航栏,以Firebase Vuex Auth 作为主要文本。它还包含了不同的文本,供用户根据其登录状态查看。

我们还使用router-link 将这些按钮链接到相应的页面。

接下来,在src 文件夹中,创建一个views 文件夹。在这个目录中,我们将创建以下页面。

  • Home.vue - 这将是主页。
  • Login.vue - 这将有一个登录页面。
  • Signup.vue - 这将有一个注册页面。

打开Home.vue 页面并粘贴以下代码。

<template>
  <div class="mt-4">
    <div v-for="blog in blogs" :key="blog.id">
      <div class="mt-4 mb-4">
        <h3 class="text-xl underline">{{ blog.title }}</h3>
        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Pariatur aspernatur consectetur doloremque sunt ducimus enim iure animi fugit nulla et! Perferendis autem deleniti quo eum corrupti reiciendis voluptatem ab ducimus?</p>
      </div>
    </div>
  </div>
</template>

<script>
import { ref } from 'vue'
export default {
  setup() {
    const blogs = ref([
      { title: 'What is programming?', id: 1 },
      { title: 'What is JS?', id: 2 },
      { title: 'What is Python?', id: 3 },
    ])
    return { 
      blogs
    }
  }
}
</script>

代码解释。

在上面的代码中,我们使用了Vue的setup()钩子,并创建了一个blogs 数组,其中包含3个对象:titleid

然后我们通过blogs 数组在template 部分进行映射,并使用blog.id 作为键。

接下来,打开Login.vue 文件并粘贴以下代码。

<template>
  <form @submit.prevent="handleSubmit" class="mt-4 flex flex-col">
    <h3 class="text-xl underline">Login</h3>

    <label for="email">Email:</label>
    <input class="border w-4/12" type="email" name="email" v-model="email" required>

    <label for="email">Password:</label>
    <input class="border w-4/12" type="password" name="password" v-model="password" required>

    <button class="w-max mt-4 px-4 py-2 text-center rounded-full bg-blue-500 text-white">Login</button>
    <div v-if="error">{{ error }}</div>  
  </form>
</template>

<script>
import { ref } from 'vue'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'

export default {
  setup() {
    const email = ref('')
    const password = ref('')
    const error = ref(null)

    const store = useStore()
    const router = useRouter()

    const handleSubmit = async () => {
      try {
        await store.dispatch('login', {
          email: email.value,
          password: password.value
        })
        router.push('/')
      }
      catch (err) {
        error.value = err.message
      }
    }
    return { handleSubmit, email, password, error }
  }
}
</script>

在上面的代码中,我们已经创建了一个有两个输入字段(电子邮件和密码字段)的登录表单,一个提交按钮和一个div ,如果有错误,就显示错误。

setup() 钩子中,我们有一个异步的handleSubmit 函数,从商店中调度login 动作。

当调度这个动作时,emailpassword 被作为参数传入。

当登录尝试成功时,用户会被重定向到主页上。如果遇到错误,表格上会显示错误信息。

最后,打开Signup.vue 文件并粘贴以下代码。

<template>
  <form @submit.prevent="handleSubmit" class="mt-4 flex flex-col">
    <h3 class="text-xl underline">Sign up</h3>

    <label for="email">Email:</label>
    <input class="border w-4/12" type="email" name="email" v-model="email" required>

    <label for="email">Password:</label>
    <input class="border w-4/12" type="password" name="password" v-model="password" required>

    <button class="w-max mt-4 px-4 py-2 text-center rounded-full bg-blue-500 text-white">Sign up</button>
    <div v-if="error">{{ error }}</div>
  </form>
</template>

<script>
import { ref } from 'vue'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'

export default {
  setup() {
    const email = ref('')
    const password = ref('')
    const error = ref(null)

    const store = useStore()
    const router = useRouter()

    const handleSubmit = async () => {
      try {
        await store.dispatch('signup', {
          email: email.value,
          password: password.value
        })
        router.push('/')
      }
      catch (err) {
        error.value = err.message
      }
    }

    return { handleSubmit, email, password, error }
  }
}
</script>

上述代码使用的逻辑与Login.vue 页面相同。

设置路由

src 文件夹中,创建一个名为router 的文件夹。在这个文件夹中,创建一个index.js 文件并粘贴以下代码。

import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Signup from '../views/Signup.vue'
import Login from '../views/Login.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/signup',
    name: 'Signup',
    component: Signup
  },
  {
    path: '/login',
    name: 'Login',
    component: Login
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

代码解释。

在上面的代码中,我们已经导入了所有的views 。然后我们创建了一个routes 数组,其中包含3个对象。

这些对象有路径和相应的组件,以便在访问该路径时呈现。然后我们使用createRouter() 方法创建我们的路由器。

配置Vue应用程序以使用路由器和商店

为了实现这一点,打开main.js 文件,用下面的代码替换现有的代码。

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './index.css'

// import store
import store from './store/index'

createApp(App).use(router).use(store).mount('#app')

最后,打开App.vue 文件,用下面的代码替换现有的代码。

<template>
  <div class="w-4/5 mx-auto mt-4">
    <Navbar />
    <router-view/>
  </div>
</template>

<script>
import Navbar from './components/Navbar'
export default {
  components: {Navbar}
}
</script>

测试应用程序

运行下面的代码,启动一个本地开发服务器。

npm run serve

在你的浏览器上进入localhost:8080 ,你会看到这个屏幕。

Test Pic

从这里你可以测试登录和注册的动作。

总结

在这篇文章中,我们讨论了如何在Firebase、Vue.js应用程序中实现认证。

然而,这个项目还可以进一步改进。例如,你可以添加更多的登录选项和添加自定义错误信息。