NuxtJS状态更改和Firebase身份验证

时间:2020-04-01 13:13:48

标签: firebase vue.js firebase-authentication nuxt.js

我仍然是nuxt的初学者,所以请原谅任何错误。

我正在使用nuxt https://firebase.nuxtjs.org/的“官方” firebase模块来访问诸如auth signIn和singOut之类的firebase服务。

这有效。

但是,我在通用模式下使用nuxt,但是无法在页面获取函数中访问它。因此,我的解决方案是将此信息保存在vuex存储中,并在更改时进行更新。

因此,一旦用户登录或Firebase身份验证状态更改,就需要在vuex存储中进行状态更改。

当前,当用户登录或firebase身份验证状态更改时,如果用户仍在登录,我将状态保存到我的商店中,如下所示:

const actions = {
  async onAuthStateChangedAction(state, { authUser, claims }) {
    if (!authUser) {
      // claims = null
      // TODO: perform logout operations
    } else {
      // Do something with the authUser and the claims object...
      const { uid, email } = authUser
      const token = await authUser.getIdToken()

      commit('SET_USER', { uid, email, token })
    }
  }
}

我也有一个突变,其中设置了状态,使用吸气剂来获取状态和实际状态对象,以及存储初始状态:

const mutations = {
  SET_USER(state, user) {
    state.user = user
  }
}

const state = () => ({
  user: null
})

const getters = {
  getUser(state) {
    return state.user
  }
}

我的问题是,在我的许多页面上,我都使用fetch方法从API获取数据,然后将这些数据存储在vuex存储中。

此获取方法使用axios进行api调用,如下所示:

async fetch({ store }) {
  const token = store.getters['getUser'] //This is null for a few seconds
  const tempData = await axios
       .post(
         my_api_url,
         {
           my_post_body
         },
         {
           headers: {
             'Content-Type': 'application/json',
             Authorization: token
           }
         }
       )
    .then((res) => {
      return res.data
    })
    .catch((err) => {
    return {
    error: err
    }
    console.log('error', err)
    })
    store.commit('my_model/setData', tempData)
 }

Axios需要我的Firebase用户ID令牌作为发送到API进行授权的标头的一部分。

运行fetch方法时,状态尚未始终更改或更新,因此,用户状态在状态更改之前仍为null,这通常是大约一秒钟,这对我来说是个问题我需要商店中的令牌来进行我的api调用。

在fetch方法内进行axios api调用之前,如何等待store.user状态完成更新/不为null?

我已经考虑过在用户登录时使用cookie来存储此信息。然后,在fetch方法内部,我可以使用cookie来获取令牌,而不必等待状态更改。我使用这种方法的问题在于,cookie在更新其令牌之前还需要等待状态更改,这意味着它将在初始页面加载时使用旧的令牌。我可能仍会选择此解决方案,只是感觉这是解决此问题的错误方法。有没有更好的方法来处理这种难题?

此外,在访存过程中,第一次加载将由服务器进行,​​因此我可以从cookie中获取令牌,但是下一次加载将从客户端进行,因此如果存储,我该如何检索令牌呢?加载时值仍为空?

编辑:

我选择了SPA模式。经过长时间的认真思考,我真的不需要nuxt服务器,并且SPA模式具有“类似服务器的”行为,您仍然可以在页面渲染之前使用asyncdata和fetch来获取数据,中间件仍然可以工作,并且身份验证实际上可以在不需要使客户端和服务器与访问令牌等保持同步的情况下工作。将来,我仍然希望看到一种更好的解决方案,但就目前而言,SPA模式可以正常工作。

2 个答案:

答案 0 :(得分:1)

我遇到了这个问题,正在寻找类似问题的解决方案。在回答这个问题之前,我在另一个答案中提到了类似的解决方案,我正在寻找的是实现细节。

我使用 nuxt.js,我想到的第一种方法是制作一个 layout 组件并仅在用户通过身份验证时呈现 <Nuxt/> 指令,但使用这种方法,我可以只有一个布局文件,如果我有多个布局文件,我将不得不在每个布局中实现相同的预认证机制,尽管这是可行的,因为现在我不是在每个页面中都实现它,而是在每个页面中实现布局应该少得多。

我找到了一个更好的解决方案,那就是在 nuxt 中使用 middlewares,您可以返回一个承诺或使用带有中间件的 async-await 来停止应用程序安装过程,直到该承诺得到解决。这是示例代码:

// middleware/auth.js
export default async function ({ store, redirect, $axios, app }) {
  if (!store.state.auth) { // if use is not authenticated
    if (!localStorage.getItem("token")) // if token is not set then just redirect the user to login page
      return redirect(app.localePath('/login'))
    try {
      const token = localStorage.getItem("token");
      const res = await $axios.$get("/auth/validate", { // you can use your firebase auth mechanism code here
        headers: {
          'Authorization': `Bearer ${token}`
        }
      });
      store.commit('login', { token, user: res.user }); // now just dispatch a login action to vuex store
    }
    catch (err) {
      store.commit('logout'); // preauth failed, so dispatch logout action which will clear localStorage and our Store
      return redirect(app.localePath('/login'))
    }
  }
}

现在您可以在页面/布局组件中使用此中间件,如下所示:

<template>
  ...
</template>
<script>
export default {
  middleware: "auth",
  ...
}
</script>

答案 1 :(得分:0)

解决此问题的一种方法是在安装应用程序之前先进行firebase登录。

从firebase获取令牌,将其保存在vuex中,只有在挂载应用程序之后。 这样可以确保在页面加载时,您将Firebase令牌保存在商店中。

添加对您不登录即不希望访问的页面的路由的检查,以在存储中查找令牌(一个或多个),并在不存在令牌的情况下重定向到另一条路由。