Javascript 试图使firebase.auth().currentUser成为承诺

Javascript 试图使firebase.auth().currentUser成为承诺,javascript,firebase,vue.js,firebase-authentication,vuex,Javascript,Firebase,Vue.js,Firebase Authentication,Vuex,当用户登录时,我试图将其发送到受限页面。所以我通过检查用户对象来保护路由。问题是,当用户创建或登录时,身份验证不会立即更改,因此在创建或登录后,firebase.auth()。currentUser可以在几毫秒内返回null。因此,如果我将它们发送到页面,它将返回一个错误 这就是我试图做的,让路由等待一段时间,看看auth是否改变。我想知道这段代码是否有问题,或者是否有更好的编写方法 另外,我知道我可以检查firebase.auth().onAuthStateChanged,但我不明白在用户创建

当用户登录时,我试图将其发送到受限页面。所以我通过检查用户对象来保护路由。问题是,当用户创建或登录时,身份验证不会立即更改,因此在创建或登录后,
firebase.auth()。currentUser
可以在几毫秒内返回
null
。因此,如果我将它们发送到页面,它将返回一个错误

这就是我试图做的,让路由等待一段时间,看看auth是否改变。我想知道这段代码是否有问题,或者是否有更好的编写方法

另外,我知道我可以检查
firebase.auth().onAuthStateChanged
,但我不明白在用户创建或登录时如何使用它。它只是在后台运行,我不能在没有上下文的情况下更改身份验证时向用户发送路由。它也没有超时

getUser( { commit } ) {
  return new Promise( ( resolve, reject )=> {
    let user, i = 0
    function checkForUser() {
      setTimeout( ()=> {
        i++
        user = firebase.auth().currentUser
        if ( user ) {
          router.push( { path: '/restricted' } )
          resolve()
        } else if ( i > 30 ) {
          reject( { message: 'Something went wrong, please try again.' } )
        } else {
          checkForUser()
        }
      }, 100 )
   }  
   checkForUser()
  } )
},

您可以将选择的
AuthProvider
getRedirectResult
方法一起使用
signInWithRedirect
方法。例如,谷歌:

firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
        firebase.auth().getRedirectResult().then(function(result) {
            if (result.additionalUserInfo && result.additionalUserInfo.isNewUser) {
                // User just created.
            }
            if (result.user) {
                // User just signed in.
            }
        });
        // User is signed in.
    }
    else {
        // User is signed out.
        firebase.auth().signInWithRedirect(new firebase.auth.GoogleAuthProvider());
    }
});

更多信息:

这是一个很长的答案,因为Firebase尚未来到谈判桌上,并采取任何行动


下面是我过去的做法,在Vuex中同步用户

对于这一点,我有两个突变和一个方便的getter,但没有什么特别的

状态:{
用户:空
},
吸气剂:{
isAuthenticated:state=>typeof state.user=='object'&&state.user!==null
},
突变:{
登录:(state,user)=>(state.user=user),
注销:状态=>(state.user=null)
}
我有一个
firebase/index.js
文件,用于配置firebase应用程序,如下所示

从“firebase/app”导入firebase
导入“firebase/auth”
//导入任何其他Firebase库,如firestore等
从“./config”导入配置
从“../store”导入存储区//导入Vuex存储区
firebase.initializeApp(配置)
export const auth=firebase.auth()
//导出其他Firebase位,如db等
const onAuthStateChangedPromise=新承诺((解决、拒绝)=>{
auth.onAuthStateChanged(用户=>{
store.commit(用户!==null?'LOGIN':'LOGOUT',用户)
解析(用户)
},err=>{
拒绝(错误)
})
})
导出const onAuthStateInit=()=>onAuthStateChangedPromise
onAuthStateChanged
侦听器使存储与用户的身份验证状态保持同步,但外部承诺只解析一次(忽略对
resolve()
的后续调用)。由于promises的这一特性,onAuthStateChangedPromise可用于检测Firebase身份验证系统何时完成其初始化阶段

然后,我将该承诺公开为一个名为
onAuthStateInit
的函数

在我的路由器中,我使用名为
public
meta
标志来确定路由是否可公开访问(大多数路由没有,这意味着它们需要身份验证)

我的全球导航卫士看起来像这样

从“/firebase”导入{onAuthStateInit}
//定义路由、新VueRouter等
路由器.beforeach(异步(到、从、下一个)=>{
等待onAuthStateInit()//等待验证系统初始化
if(to.matched.every(route=>route.meta.public)| | store.getters.isAuthenticated){
下一个()
}否则{
下一步({name:'登录'})//重定向到登录页
}
})
您可以在需要等待第一页加载验证初始化完成的任何位置使用
await onAuthStateInit()
。您可以根据需要多次调用它,它只会等待一次。一旦授权初始化完成,此承诺将立即解决

我的
登录
页面使用Firebase身份验证UI,定义了以下回调

从“firebase/app”导入firebase
从“firebaseui”导入*作为firebaseui
从“../firebase”导入{auth}
导入“firebaseui/dist/firebaseui.css”
const ui=new firebaseui.auth.AuthUI(auth)
导出默认值{
挂载(){
//ref只是我模板中的一个示例
const container=this.$refs.firebaseuiAuthContainer
开始(容器,{
//签名等
回调:{
SignInsessWithAuthResult:authResult=>{
this.$router.push({name:'home'})//转到主页或任何地方
},
signInFailure:err=>{
//处理登录错误
}
}
})    
}
}

您不必使用身份验证UI。对当前用户的身份验证状态的任何更改都将被
onAuthStateChange
侦听器捕获,因此如果需要,您可以使用带有*()方法的手动
身份验证登录。

似乎您还想显示登录用户的代码,因为此处显示的内容取决于其他代码,还有你可能如何处理它的结果。这有一个很长的GitHub问题(他们花了太长时间来修复IMO),列出了一些很好的解决方法~@DougStevenson我实际上在几个不同的地方使用它,我需要用户对象出现。所以我可以运行这个函数并等待它通过或失败。但不知何故,它感觉有点混乱,不知道是否有更干净的方法来实现这一点。@Phil我见过线程,但解决方案似乎无法处理超时,如果用户对象没有填充,它就会卡住。为什么onAuthStateInit只运行一次?它不是每次都创建一个新的承诺吗?@KelvinZhao否,您可以看到它返回仅创建一次的
onAuthStateChangedPromise
。我之所以将其作为函数,是因为
await-onAuthStateInit()
看起来比
await-onAuthStateChangedPromise
Ah。。。因此,当您
返回新承诺时,它会在第一次解析时锁定它,而如果您
新承诺时,它会每次运行一个新承诺?是吗