【问题标题】:Nuxt newbie - Firebase auth not working on refreshNuxt 新手 - Firebase 身份验证无法刷新
【发布时间】:2020-04-14 07:26:58
【问题描述】:

我已经搜索并尝试了大量示例和不同的东西,但仍然完全停留在这里 - 我已经为此扯了 2 天的头发…… 我有一个常见的问题,如果我登录并单击链接,我的应用程序可以正常工作,但如果我直接在浏览器中刷新或点击 URL,Firebase 似乎认为我没有经过身份验证的会话。

编辑所以在想了更多之后,我认为这是因为刷新时,Vue server正在请求。单击链接时,客户端会发出请求...最大的区别是没有在服务器请求上设置或发送会话/cookie。 是触发重定向的解决方案吗?或者有没有办法在页面加载时发送浏览器的 cookie/会话?还是我在 Vue 和 Firebase 之间建立某种服务器到服务器的身份验证,然后通过 Vue/Vuex 管理登录状态?

这是 FB 返回的错误:

Error during getting LIST of presentations! FirebaseError: [code=permission-denied]: Missing or insufficient permissions. 

这是我正在做的事情:

首先在我的 store/index.js 中,我们解码用户数据的 cookie 并将其发送到一个名为 setUserLoggedIn 的操作(我知道我设置了两次相同的值,但为了完整性将其保留在那里 :))

这段代码似乎按预期工作(即,它总是在 Nuxt 启动时执行。我们这样做是为了确保在我们做任何事情之前我们的 Vuex 存储中的 cookie 中有用户数据)。它解码 cookie/将预期值发送到 setUserLoggedin

    import { getUserFromCookie } from '@/helpers'
export const actions = {
  async nuxtServerInit({ dispatch }, { req }) {
    const user = getUserFromCookie(req)
    console.log('This code fires first with user ' + JSON.stringify(user))
    if (user) {
      console.log('Found a user cookie - maybe we can log them in')
      await dispatch('user/setUserLoggedin', {
        email: user.email,
        uid: user.user_id,
        thisUserid: user.user_id
      })
    }
  }
}

然后我们通过 2 个变更将登录状态和用户详细信息提交回 Vuex 的状态,然后确认用户使用 Firebase 登录的事实:

 setUserLoggedin({ commit }, user) {

    commit('LOGIN_STATUS', true)
    console.log(`Re-affirming login user object is ${JSON.stringify(user)}`)
    commit('LOGIN_USER', {
      loginInstanceId: 'a-key-to-track-each-login-session',
      useruniqueid: user.thisUserid,
      emailaddress: user.email,
      uid: user.thisUserid
    })
    return UserService.affirmLogin(user)
  },

最后,我尝试检查我是否与 Firebase 进行了会话(firebase.auth().currentUser 返回未定义)。使用其他 Firebase 命令来监听状态变化或类似的东西也没有运气......从字面上看,我尝试过的一切都是空白。

  async affirmLogin(myuser) {
    const currentUser = await firebase.auth().currentUser
    console.table(currentUser)
  },

我也在设置一个带有 Firebase 令牌的令牌

await firebase
        .auth()
        .signInWithEmailAndPassword(user.emailaddress, user.password)
        .then(() => {
          firebase.auth().onAuthStateChanged(user => {
            currentUser = user.uid
          })
        })
      const token = await firebase.auth().currentUser.getIdToken(true)
      Cookies.set('access_token', token) // saving token in cookie for server rendering

我已经尝试了上百万种不同的方法 - 从配置我的 Vuex 状态/getter 和 Firebase 命令,到注释我的代码的生命、调试等,但我无法找出原因这行不通。 Firebase 似乎在刷新时忽略或看不到任何现有会话,尽管我有一个 cookie 并且我认为数据在 Vuex 存储中。

但是,如果我通过 UI 导航到的页面点击上面的路线(即我让表单提交按钮点击确认登录),它确实有效。

我认为问题在于我的会话有问题,但我看不出它可能是什么。我也不确定 Firebase 应该如何在刷新时收集用户 ID。我见过的其他例子似乎“只是工作”,但不适合我:(非常感谢任何帮助!

谢谢

【问题讨论】:

  • 我认为您的 setUserLoggedin 操作也必须是异步的:async setUserLoggedin...
  • 然后在这个动作里面:return await UserService.affirmLogin(user)
  • 谢谢,但恐怕没有用:(同样的错误

标签: javascript firebase vue.js nuxt.js


【解决方案1】:

TBH 我不知道 Vue、Nuxt、 Firebase,但我的第一个猜测是,当您要求 Firebase 返回 currentUser 时,它是尚未完全初始化或类似的东西。 Firebase 文档似乎同意:

注意:currentUser 也可能为 null,因为 auth 对象尚未完成初始化。如果您使用观察者来跟踪用户的登录状态,则无需处理这种情况。

您是否尝试过使用身份验证状态观察器?它看起来像这样:

firebase.auth().onAuthStateChanged(function(user) {
  if (user) {
    // User is signed in.
  } else {
    // No user is signed in.
  }
});

我建议您尽早在代码中进行设置,以确保您不会错过身份验证状态更改。你可以从这样的开始:

setUserLoggedin({ commit }, user) {
  const userPromise = new Promise((resolve, reject) => {
    firebase.auth().onAuthStateChanged(function(user) {
      if (user) {
        // User is signed in.
        console.log('got user', user);
        resolve(true);
      } else {
        // No user is signed in.
        resolve(false);
      }
    });
  });

  commit('LOGIN_STATUS', true);

  console.log(`Re-affirming login user object is ${JSON.stringify(user)}`);
  commit('LOGIN_USER', {
    loginInstanceId: 'a-key-to-track-each-login-session',
    useruniqueid: user.thisUserid,
    emailaddress: user.email,
    uid: user.thisUserid,
  });

  return userPromise;
}

我很确定这不足以作为最终解决方案,但它可能会帮助您走上正确的轨道如果我的猜测是正确的

【讨论】:

  • 再次感谢 - 这并没有真正产生任何影响 - 我实际上(有!)那个观察者也设置了(使用 async/await),它似乎只会解析为 false。我不太确定我是否理解它应该如何持续观察上述语法中的状态,因为在我看来,只要承诺解决了真或假,就是这样。我觉得当我的代码继续运行时状态没有得到解决是问题的一部分,但我只是不知道如何验证或修复它。
  • 你是对的 - 在承诺解决/拒绝后代码将继续运行。上面的例子只是为了看看使用观察者是否有帮助! : ] 但是,即使在 promise 解决后,观察者 应该 继续调用它的回调,因此每当新用户登录时都会打印 console.log('got user', user);(假设 Firebase 是这样工作的 - 我真的不知道)。因此,如果 never 打印了“got user”,则 可能 意味着 Firebase 并没有真正看到用户,问题出在其他地方。
  • 是的,我在尝试使其正常工作的大约 2 小时时也有同样的想法:) 我还没有找到让它以这种方式运行的方法。也许问题出在其他地方,但据我所见,当我们尝试进行经过身份验证的调用时,会话 cookie 和 vuex 状态都使用用户标识符设置,所以我不清楚为什么这不起作用。再次感谢,我会继续关注这个
  • 我不希望这变成一个论坛,所以这是我最后的想法。除非您使用 Firebase 的特殊 Vuex 绑定而不是官方 SDK,否则它可能无法从商店获取用户详细信息。如果我是对的,您可能应该明确告知 Firebase 有一个用户登录。换句话说,是什么让您认为实际上应该有一个 currentUser?
  • 谢谢。我已经浏览了无数示例的代码,但我看不出它们中的任何一个是如何获取用户详细信息的。我完全不知道现在该做什么。感谢您的帮助 - 希望我能解决!
【解决方案2】:

我有同样的问题,刷新或重新加载后收到未经身份验证的错误,问题来自用户端点的propertyName,如果你直接返回用户,而不是对象'user':{...},你应该把propertyName : false放在nuxt的auth选项中config,你可以通过直接执行这段代码来检查auth会收到什么结果

let user = await this.$auth.requestWith(    
    'local',    //strategy name
    null,       //endpoint
    { url: '/api/user', method: 'get', propertyName: false } // options.endpoints.user
);

【讨论】:

  • 谢谢 - 最后我通过强制某些页面在类似 SPA 的状态下运行来解决这个问题。这是因为即使刷新也不允许发生对 Firebase 的服务器请求。在代表客户端发送请求时,我试图让 Nuxt/Firebase 正常运行时遇到了太多问题。
猜你喜欢
  • 2021-09-06
  • 1970-01-01
  • 2016-09-19
  • 2018-12-14
  • 2020-08-05
  • 1970-01-01
  • 2020-12-12
  • 2017-11-08
  • 2019-02-27
相关资源
最近更新 更多