试图让 firebase.auth().currentUser 成为一个承诺 [英] Attempting to make firebase.auth().currentUser a promise
问题描述
当用户登录时,我试图将他们发送到受限页面.所以我通过检查用户对象来保护路线.问题是当用户创建或登录时,auth 不会立即改变,所以创建或登录后,firebase.auth().currentUser
可以返回 null代码> 几毫秒.所以如果我将它们发送到页面,它会返回一个错误.
When a user logs in, I'm trying to send them to a restricted page. So I'm protecting the route by checking for the user object. The problem is that when a user is created or logging in, the auth doesn't immediately change, so after creating or logging in, firebase.auth().currentUser
can return null
for a couple of milliseconds. So if I send them to the page, it will return an error.
这就是我试图做的事情,试图让路由等待一段时间以查看身份验证是否发生变化.我想知道代码是否有任何问题或编写此代码的更好方法.
This is what I'm trying to do in an attempt for the route to wait a while to see if the auth changes. I'm wondering if there is any issues with the code or a better way to write this.
附言我知道我可以检查 firebase.auth().onAuthStateChanged
,但我不明白如何在用户创建或登录时使用它.它只是在后台运行,我可以't 只是在没有上下文的情况下更改身份验证时向用户发送路由.它也没有超时.
P.S. I know that I can check for firebase.auth().onAuthStateChanged
, but I don't understand how I can use it upon user creation or log in. It just runs in the background and I can't just send users a route when auth changes with no context. It also doesn't have a timeout.
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()
} )
},
推荐答案
这是一个很长的答案,因为 Firebase 还没有来到谈判桌前对 https://github.com/firebase/firebase-js-sdk/issues/462
This is a long answer because Firebase has yet to come to the table and do anything about https://github.com/firebase/firebase-js-sdk/issues/462
这是我过去的做法,在 Vuex 中同步用户.
Here's how I've done it in the past, synchronising the user in Vuex.
为此,我有两个突变和一个方便的吸气剂,但没有什么特别的
For this, I've got two mutations and a handy getter but there's nothing too special there
state: {
user: null
},
getters: {
isAuthenticated: state => typeof state.user === 'object' && state.user !== null
},
mutations: {
LOGIN: (state, user) => (state.user = user),
LOGOUT: state => (state.user = null)
}
我有一个 firebase/index.js
文件,用于配置如下所示的 Firebase 应用
I have a firebase/index.js
file for configuring the Firebase App that looks like this
import firebase from 'firebase/app'
import 'firebase/auth'
// import any other Firebase libs like firestore, etc
import config from './config'
import store from '../store' // import the Vuex store
firebase.initializeApp(config)
export const auth = firebase.auth()
// export other Firebase bits like db, etc
const onAuthStateChangedPromise = new Promise((resolve, reject) => {
auth.onAuthStateChanged(user => {
store.commit(user !== null ? 'LOGIN' : 'LOGOUT', user)
resolve(user)
}, err => {
reject(err)
})
})
export const onAuthStateInit = () => onAuthStateChangedPromise
onAuthStateChanged
侦听器使存储与用户的 auth 状态保持同步,但外部承诺仅解析一次(对 resolve()
被忽略).由于 Promise 的这一特性,onAuthStateChangedPromise
可用于检测 Firebase 身份验证系统何时完成其初始化阶段.
The onAuthStateChanged
listener keeps the store in sync with the user's auth status yet the outer promise only resolves once (subsequent calls to resolve()
are ignored). Due to this feature of promises, the onAuthStateChangedPromise
can be used to detect when the Firebase authentication system has completed its initialisation phase.
然后我将该承诺公开为名为 onAuthStateInit
的函数.
I've then exposed that promise as a function named onAuthStateInit
.
在我的路由器中,我使用名为 public
的 meta
标志来确定路由是否可公开访问(大多数路由没有它,这意味着他们需要身份验证).
In my router, I use a meta
flag named public
to determine if a route is publicly accessible or not (most routes don't have it which means they need authentication).
我的全局导航守卫看起来像这样
My global navigation guard looks like this
import { onAuthStateInit } from './firebase'
// define routes, new VueRouter, etc
router.beforeEach(async (to, from, next) => {
await onAuthStateInit() // wait for auth system to initialise
if (to.matched.every(route => route.meta.public) || store.getters.isAuthenticated) {
next()
} else {
next({ name: 'sign-in' }) // redirect to sign-in page
}
})
您可以在需要等待第一页加载身份验证初始化完成的任何地方使用 await onAuthStateInit()
.您可以根据需要多次调用它,它只会等待一次.身份验证初始化完成后,此承诺将立即解决.
You can use await onAuthStateInit()
anywhere where you would need to wait for that first-page-load auth initialisation to complete. You can call this as many times as is necessary and it will only ever wait one time. Once the auth initialisation is complete, this promise will resolve instantly.
我的登录
页面使用 Firebase Auth UI 并定义了以下回调
My sign-in
page uses the Firebase Auth UI with the following callbacks defined
import firebase from 'firebase/app'
import * as firebaseui from 'firebaseui'
import { auth } from '../firebase'
import 'firebaseui/dist/firebaseui.css'
const ui = new firebaseui.auth.AuthUI(auth)
export default {
mounted () {
// the ref is just a <div> in my template
const container = this.$refs.firebaseuiAuthContainer
ui.start(container, {
// signInOptions, etc
callbacks: {
signInSuccessWithAuthResult: authResult => {
this.$router.push({ name: 'home' }) // go to homepage or wherever
},
signInFailure: err => {
// handle sign-in error
}
}
})
}
}
You don't have to use the Auth UI. Any changes to the authenticated state of the current user will be caught by the onAuthStateChange
listener so you can use the manual auth.SignInWith*()
methods if you want.
这篇关于试图让 firebase.auth().currentUser 成为一个承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!