无法加载 currentUser
Can't get currentUser on load
当尝试检查用户是否通过 firebase.auth().currentUser
登录时,如下所示:
if (firebase.auth().currentUser === null) {
console.log('User not signed in');
}
每当我刷新页面,或在上面导航时 returns null(即使我刚刚登录)。
奇怪的是,如果我登录
console.log(firebase.auth().currentUser) // This returns null
console.log(firebase.auth()) // Here I can inspect the object and currentUser exists...!
我真的不知道这里发生了什么。我正在使用 React 和 Redux,但我认为这并不重要。
在 firebase 初始化时是否有一个小延迟,您无法访问 currentUser?如果是这样,我如何在 firebase.auth()
的日志输出中看到它?
这是一个常见问题。
https://firebase.google.com/docs/auth/web/manage-users
你需要在 onAuthStateChanged 中添加一个观察者来检测初始状态和所有后续状态的变化,
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
始终访问 currentUser 的最佳方法是使用 vuex 和 vuex-persistedstate
//Configure firebase
firebase.initializeApp(firebaseConfig);
//When ever the user authentication state changes write the user to vuex.
firebase.auth().onAuthStateChanged((user) =>{
if(user){
store.dispatch('setUser', user);
}else{
store.dispatch('setUser', null);
}
});
上面唯一的问题是,如果用户在浏览器上按下刷新,vuex 状态将被丢弃,您必须等待 onAuthStateChange 再次触发,因此当您尝试访问 currentUser 时会得到 null。
上述代码一直有效的秘诀是使用 vuex-persisted state。
在你的 store.js 文件中
import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase/app'
Vue.use(Vuex)
import createPersistedState from "vuex-persistedstate";
export default new Vuex.Store({
plugins: [createPersistedState()],
state: {
user: null
},
getters:{
getUser: state => {
return state.user;
}
},
mutations: {
setUser(state, user){
state.user = user;
}
},
actions: {
setUser(context, user){
context.commit('setUser', user);
},
signIn(){
let provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider).then(function (result) {
})
},
signOut(){
firebase.auth().signOut();
}
}
})
您现在可以按照下面的代码示例保护路由器中的路由。
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import Search from '@/components/Search/Search'
import CreateFishingSite from '@/components/FishingSites/CreateFishingSite'
Vue.use(Router);
import store from './store'
import firebase from 'firebase'
let router = new Router({
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/search/:type',
name: 'Search',
component: Search
},
{
path: '/fishingsite/create',
name: 'CreateFishingSite',
component: CreateFishingSite,
meta: {
requiresAuth: true
}
}
]
})
router.beforeEach(async (to, from, next)=>{
let currentUser = store.state.user;
console.log(currentUser);
let requriesAuth = to.matched.some(record => record.meta.requiresAuth);
if(requriesAuth && !currentUser){
await store.dispatch('signIn');
next('/')
}else{
next()
}
})
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
var user = firebase.auth().currentUser;
if(user != null){
var io=user.uid;
window.alert("success "+io);
}
} else {
// No user is signed in.
Window.reload();
}
});
首先检查用户是否存在,然后通过
获取它的 ID
firebase.auth().currentUser.uid
// On component load.
componentDidMount = () => this.getAuthStatus();
// Get firebase auth status.
getAuthStatus = () => {
firebase.auth().onAuthStateChanged((resp) => {
// Pass response to a call back func to update state
this.updateUserState(resp);
});
}
// update state
updateUserState = (resp) => {
this.setState({
user: resp
})
}
// Now you can validate anywhere within the component status of a user
if (this.state.user) { /*logged in*/}
一种简单的方法是添加挂起状态。
这是一个使用钩子的反应示例:
// useAuth.ts
import { useState, useEffect } from 'react'
import { auth } from 'firebase'
export function useAuth() {
const [authState, setAuthState] = useState({
isSignedIn: false,
pending: true,
user: null,
})
useEffect(() => {
const unregisterAuthObserver = auth().onAuthStateChanged(user =>
setAuthState({ user, pending: false, isSignedIn: !!user })
)
return () => unregisterAuthObserver()
}, [])
return { auth, ...authState }
}
// SignIn.tsx
import React from 'react'
import { StyledFirebaseAuth } from 'react-firebaseui'
import { useAuth } from '../hooks'
export default function SignIn() {
const { pending, isSignedIn, user, auth } = useAuth()
const uiConfig = {
signInFlow: 'popup',
signInOptions: [
auth.GoogleAuthProvider.PROVIDER_ID,
auth.FacebookAuthProvider.PROVIDER_ID,
],
}
if (pending) {
return <h1>waiting...</h1>
}
if (!isSignedIn) {
return (
<div>
<h1>My App</h1>
<p>Please sign-in:</p>
<StyledFirebaseAuth uiConfig={uiConfig} firebaseAuth={auth()} />
</div>
)
}
return (
<div>
<h1>My App</h1>
<p>Welcome {user.displayName}! You are now signed-in!</p>
<a onClick={() => auth().signOut()}>Sign-out</a>
</div>
)
}
如果您正在寻找用于与 firebase 反应的复制和粘贴 Auth 路由:
const AuthRoute = ({ component: Component, ...rest }) => {
const [authenticated, setAuthenticated] = useState(false)
const [loadingAuth, setLoadingAuth] = useState(true)
useEffect(() => {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
setAuthenticated(true)
} else {
setAuthenticated(false)
}
setLoadingAuth(false)
})
}, [])
return loadingAuth ? 'loading...' : (
<Route
{...rest}
render={props =>
authenticated ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: '/user/login' }} />
)}
/>
)
}
最好的方法是使用承诺并仅在响应后实例化路由器,类似于:
store.dispatch('userModule/checkAuth').then(() => {
// whatever code you use to first initialise your router, add it in here, for example
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
})
在 checkAuth 操作中是您做出承诺的地方,如下所示:
checkAuth ({ commit }) {
return new Promise((resolve, reject) => {
firebase.auth().onAuthStateChanged(async (_user) => {
if (_user) {
commit('setUser', _user)
} else {
commit('setUser', null)
}
console.log('current user in checkAuth action:', _user)
resolve(true)
})
})
h/t 致 aaron k saunders - 我的这个解决方案的来源。
Promise-wise,共有三个选项:
// best option
const user1 = await new Promise((resolve: any, reject: any) =>
firebase.auth().onAuthStateChanged((user: any) =>
resolve(user), (e: any) => reject(e)));
console.log(user1);
// sometimes does not display correctly when logging out
const user2 = await firebase.auth().authState.pipe(first()).toPromise();
console.log(user2);
// technically has a 3rd state of 'unknown' before login state is checked
const user3 = await firebase.auth().currentUser;
console.log(user3);
如果您希望用户只有在通过身份验证后才能访问某个页面,如果没有通过身份验证则重定向到主页,以下代码可能会有所帮助:
在反应中:
使用以下代码创建一个组件:
import { onAuthStateChanged } from "@firebase/auth";
import { Route, Redirect } from "react-router-dom";
import { auth } from "../firebase/config";
import { useState, useEffect } from "react";
const GuardedRoute = ({ component, path }) => {
const [authenticated, setAuthenticated] = useState(false);
const [authCompleted, setAuthCompleted] = useState(false);
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
setAuthenticated(true);
} else {
setAuthenticated(false);
}
setAuthCompleted(true);
});
}, []);
return authCompleted ? (
authenticated ? (
<Route path={path} component={component} />
) : (
<Redirect to="/" />
)
) : (
""
);
};
export default GuardedRoute;
并在 app.js 中使用:
import RouterPage from "./pages/RouterPage";
<GuardedRoute path="/router-page" component={RouterPage} />
在 Vue 中:
在路由器文件中使用:
const guardSuccess = (to, from, next) => {
let gUser = auth.currentUser
if (gUser) {
next()
} else {
next({ name: "Home" })
}
}
并在要限制访问的页面的路由中添加:
{
path: "/router-page",
name: "routerPage",
component: () => import("../views/routerPage.vue"),
beforeEnter: guardSuccess
}
当尝试检查用户是否通过 firebase.auth().currentUser
登录时,如下所示:
if (firebase.auth().currentUser === null) {
console.log('User not signed in');
}
每当我刷新页面,或在上面导航时 returns null(即使我刚刚登录)。
奇怪的是,如果我登录
console.log(firebase.auth().currentUser) // This returns null
console.log(firebase.auth()) // Here I can inspect the object and currentUser exists...!
我真的不知道这里发生了什么。我正在使用 React 和 Redux,但我认为这并不重要。
在 firebase 初始化时是否有一个小延迟,您无法访问 currentUser?如果是这样,我如何在 firebase.auth()
的日志输出中看到它?
这是一个常见问题。 https://firebase.google.com/docs/auth/web/manage-users 你需要在 onAuthStateChanged 中添加一个观察者来检测初始状态和所有后续状态的变化,
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
始终访问 currentUser 的最佳方法是使用 vuex 和 vuex-persistedstate
//Configure firebase
firebase.initializeApp(firebaseConfig);
//When ever the user authentication state changes write the user to vuex.
firebase.auth().onAuthStateChanged((user) =>{
if(user){
store.dispatch('setUser', user);
}else{
store.dispatch('setUser', null);
}
});
上面唯一的问题是,如果用户在浏览器上按下刷新,vuex 状态将被丢弃,您必须等待 onAuthStateChange 再次触发,因此当您尝试访问 currentUser 时会得到 null。
上述代码一直有效的秘诀是使用 vuex-persisted state。
在你的 store.js 文件中
import Vue from 'vue'
import Vuex from 'vuex'
import firebase from 'firebase/app'
Vue.use(Vuex)
import createPersistedState from "vuex-persistedstate";
export default new Vuex.Store({
plugins: [createPersistedState()],
state: {
user: null
},
getters:{
getUser: state => {
return state.user;
}
},
mutations: {
setUser(state, user){
state.user = user;
}
},
actions: {
setUser(context, user){
context.commit('setUser', user);
},
signIn(){
let provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider).then(function (result) {
})
},
signOut(){
firebase.auth().signOut();
}
}
})
您现在可以按照下面的代码示例保护路由器中的路由。
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/components/Home'
import Search from '@/components/Search/Search'
import CreateFishingSite from '@/components/FishingSites/CreateFishingSite'
Vue.use(Router);
import store from './store'
import firebase from 'firebase'
let router = new Router({
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/search/:type',
name: 'Search',
component: Search
},
{
path: '/fishingsite/create',
name: 'CreateFishingSite',
component: CreateFishingSite,
meta: {
requiresAuth: true
}
}
]
})
router.beforeEach(async (to, from, next)=>{
let currentUser = store.state.user;
console.log(currentUser);
let requriesAuth = to.matched.some(record => record.meta.requiresAuth);
if(requriesAuth && !currentUser){
await store.dispatch('signIn');
next('/')
}else{
next()
}
})
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
var user = firebase.auth().currentUser;
if(user != null){
var io=user.uid;
window.alert("success "+io);
}
} else {
// No user is signed in.
Window.reload();
}
});
首先检查用户是否存在,然后通过
获取它的 IDfirebase.auth().currentUser.uid
// On component load.
componentDidMount = () => this.getAuthStatus();
// Get firebase auth status.
getAuthStatus = () => {
firebase.auth().onAuthStateChanged((resp) => {
// Pass response to a call back func to update state
this.updateUserState(resp);
});
}
// update state
updateUserState = (resp) => {
this.setState({
user: resp
})
}
// Now you can validate anywhere within the component status of a user
if (this.state.user) { /*logged in*/}
一种简单的方法是添加挂起状态。
这是一个使用钩子的反应示例:
// useAuth.ts
import { useState, useEffect } from 'react'
import { auth } from 'firebase'
export function useAuth() {
const [authState, setAuthState] = useState({
isSignedIn: false,
pending: true,
user: null,
})
useEffect(() => {
const unregisterAuthObserver = auth().onAuthStateChanged(user =>
setAuthState({ user, pending: false, isSignedIn: !!user })
)
return () => unregisterAuthObserver()
}, [])
return { auth, ...authState }
}
// SignIn.tsx
import React from 'react'
import { StyledFirebaseAuth } from 'react-firebaseui'
import { useAuth } from '../hooks'
export default function SignIn() {
const { pending, isSignedIn, user, auth } = useAuth()
const uiConfig = {
signInFlow: 'popup',
signInOptions: [
auth.GoogleAuthProvider.PROVIDER_ID,
auth.FacebookAuthProvider.PROVIDER_ID,
],
}
if (pending) {
return <h1>waiting...</h1>
}
if (!isSignedIn) {
return (
<div>
<h1>My App</h1>
<p>Please sign-in:</p>
<StyledFirebaseAuth uiConfig={uiConfig} firebaseAuth={auth()} />
</div>
)
}
return (
<div>
<h1>My App</h1>
<p>Welcome {user.displayName}! You are now signed-in!</p>
<a onClick={() => auth().signOut()}>Sign-out</a>
</div>
)
}
如果您正在寻找用于与 firebase 反应的复制和粘贴 Auth 路由:
const AuthRoute = ({ component: Component, ...rest }) => {
const [authenticated, setAuthenticated] = useState(false)
const [loadingAuth, setLoadingAuth] = useState(true)
useEffect(() => {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
setAuthenticated(true)
} else {
setAuthenticated(false)
}
setLoadingAuth(false)
})
}, [])
return loadingAuth ? 'loading...' : (
<Route
{...rest}
render={props =>
authenticated ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: '/user/login' }} />
)}
/>
)
}
最好的方法是使用承诺并仅在响应后实例化路由器,类似于:
store.dispatch('userModule/checkAuth').then(() => {
// whatever code you use to first initialise your router, add it in here, for example
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
})
在 checkAuth 操作中是您做出承诺的地方,如下所示:
checkAuth ({ commit }) {
return new Promise((resolve, reject) => {
firebase.auth().onAuthStateChanged(async (_user) => {
if (_user) {
commit('setUser', _user)
} else {
commit('setUser', null)
}
console.log('current user in checkAuth action:', _user)
resolve(true)
})
})
h/t 致 aaron k saunders - 我的这个解决方案的来源。
Promise-wise,共有三个选项:
// best option
const user1 = await new Promise((resolve: any, reject: any) =>
firebase.auth().onAuthStateChanged((user: any) =>
resolve(user), (e: any) => reject(e)));
console.log(user1);
// sometimes does not display correctly when logging out
const user2 = await firebase.auth().authState.pipe(first()).toPromise();
console.log(user2);
// technically has a 3rd state of 'unknown' before login state is checked
const user3 = await firebase.auth().currentUser;
console.log(user3);
如果您希望用户只有在通过身份验证后才能访问某个页面,如果没有通过身份验证则重定向到主页,以下代码可能会有所帮助:
在反应中: 使用以下代码创建一个组件:
import { onAuthStateChanged } from "@firebase/auth";
import { Route, Redirect } from "react-router-dom";
import { auth } from "../firebase/config";
import { useState, useEffect } from "react";
const GuardedRoute = ({ component, path }) => {
const [authenticated, setAuthenticated] = useState(false);
const [authCompleted, setAuthCompleted] = useState(false);
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
setAuthenticated(true);
} else {
setAuthenticated(false);
}
setAuthCompleted(true);
});
}, []);
return authCompleted ? (
authenticated ? (
<Route path={path} component={component} />
) : (
<Redirect to="/" />
)
) : (
""
);
};
export default GuardedRoute;
并在 app.js 中使用:
import RouterPage from "./pages/RouterPage";
<GuardedRoute path="/router-page" component={RouterPage} />
在 Vue 中: 在路由器文件中使用:
const guardSuccess = (to, from, next) => {
let gUser = auth.currentUser
if (gUser) {
next()
} else {
next({ name: "Home" })
}
}
并在要限制访问的页面的路由中添加:
{
path: "/router-page",
name: "routerPage",
component: () => import("../views/routerPage.vue"),
beforeEnter: guardSuccess
}