admin管理员组文章数量:1323737
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.
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( { mit } ) {
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()
} )
},
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.
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( { mit } ) {
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()
} )
},
Share
Improve this question
edited Jul 23, 2020 at 6:22
Kelvin Zhao
asked Jul 23, 2020 at 5:42
Kelvin ZhaoKelvin Zhao
2,4454 gold badges24 silver badges32 bronze badges
4
- Seems like you'd also want to show the code that signs in the user, since what you're showing here is dependent on that other code, and how you might be handling its results. – Doug Stevenson Commented Jul 23, 2020 at 5:46
- There's a nice long GitHub issue for this (that's taking far too long for them to fix IMO) that's got some good work-arounds listed ~ github./firebase/firebase-js-sdk/issues/462 – Phil Commented Jul 23, 2020 at 5:51
- @DougStevenson I'm actually using this in a couple of different places where I need the user object to be present. So I can run this function and wait for it to either pass or fail. But somehow it feels a little messy, wondering if there's a cleaner way to do this. – Kelvin Zhao Commented Jul 23, 2020 at 7:25
- @Phil I've seen the thread but the solution doesn't seem to handle a timeout and just gets stuck if the user object doesn't get populated. – Kelvin Zhao Commented Jul 23, 2020 at 7:25
3 Answers
Reset to default 6This is a long answer because Firebase has yet to e to the table and do anything about https://github./firebase/firebase-js-sdk/issues/462
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)
}
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.mit(user !== null ? 'LOGIN' : 'LOGOUT', user)
resolve(user)
}, err => {
reject(err)
})
})
export const onAuthStateInit = () => onAuthStateChangedPromise
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 pleted its initialisation phase.
I've then exposed that promise as a function named onAuthStateInit
.
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
}
})
You can use await onAuthStateInit()
anywhere where you would need to wait for that first-page-load auth initialisation to plete. You can call this as many times as is necessary and it will only ever wait one time. Once the auth initialisation is plete, this promise will resolve instantly.
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.
In 2024 you can use authStateReady()
https://firebase.google./docs/reference/js/auth.auth.md#authauthstateready
async function getUser() {
const auth = getAuth();
await auth.authStateReady();
return auth.currentUser;
}
getUser().then(user => {
console.log('user: ', user);
});
You can use the signInWithRedirect
method with AuthProvider
of your choice along with the getRedirectResult
method . For example with Google:
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());
}
});
More info: https://firebase.google./docs/reference/js/firebase.auth.Auth#methods
本文标签: javascriptAttempting to make firebaseauth()currentUser a promiseStack Overflow
版权声明:本文标题:javascript - Attempting to make firebase.auth().currentUser a promise - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742119224a2421617.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论