sourcecode

로드에서 현재 사용자를 가져올 수 없습니다.

codebag 2023. 6. 27. 22:10
반응형

로드에서 현재 사용자를 가져올 수 없습니다.

사용자가 로그인되었는지 확인하려고 할 때firebase.auth().currentUser다음과 같이:

if (firebase.auth().currentUser === null) {
  console.log('User not signed in');
}

페이지를 새로 고치거나 위에서 탐색할 때마다 null이 반환됩니다(로그인한 지 얼마 되지 않았음에도 불구하고).

이상한 것은, 만약 내가 로그에 기록한다면.

console.log(firebase.auth().currentUser) // This returns null
console.log(firebase.auth()) // Here I can inspect the object and currentUser exists...!

여기서 무슨 일이 일어나고 있는지 잘 모르겠어요.저는 리액트와 리덕스를 사용하고 있지만, 제가 말하는 것은 별로 중요하지 않습니다.

파이어베이스가 초기화되고 현재 사용자에 액세스할 수 없는 약간의 지연이 있습니까?그렇다면 의 로그 출력에서 어떻게 확인할 수 있습니까?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.
  }
});

간단한 방법은 보류 중인 상태를 추가하는 것입니다.

다음은 후크를 사용한 반응 예제입니다.

Auth.

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 }
}

사인인 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>
  )
}

currentUser에 항상 액세스할 수 있는 가장 좋은 방법은 vuex 및 vuex 지속 상태를 사용하는 것입니다.

//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 상태가 사라지고 AuthStateChange에서 다시 시작될 때까지 기다려야 하므로 현재 사용자에 액세스하려고 하면 null이 발생하는 이유입니다.

위 코드가 항상 작동하는 비결은 vuex-persisted 상태를 사용하는 것입니다.

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 경로를 복사하여 붙여넣으려는 경우:

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' }} />
            )}
        />

      )
    }

다음과 같은 세 가지 옵션이 있습니다.

업데이트: 11/26/22

Firebase 9+의 경우 다음을 수행할 수 있습니다.

참고: (이 .auth)는 Auth 개체이며 프레임워크에 따라 다릅니다.

const user1 = await firstValueFrom(authState(this.afa));

const user2 = await firstValueFrom(
  new Observable(observer => onAuthStateChanged(this.afa, observer))
);

const user3 = this.afa.currentUser;

// 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);

TL;DR:

expo sdk를 사용하여 여기에 오는 사람들을 위해.>=48또는 React Native를 업데이트한 후>=0.71화재 기지를 초기화해야 합니다.다음과 같은 사용자 지정 스토리지로 인증:

import { initializeAuth } from 'firebase/auth';
import { getApp } from 'firebase/app';
import { getReactNativePersistence } from 'firebase/auth/react-native';
import ReactNativeAsyncStorage from '@react-native-async-storage/async-storage';

const storage = getReactNativePersistence(ReactNativeAsyncStorage)
const app = getApp();

initializeAuth(app, {
  persistence: storage,
});

설명:

AsyncStorage오래 전부터 사용되지 않아 V 0.71의 React Native에서 제거되었습니다.안타깝게도 Firebase 인증은 여전히 후드 아래 통합된 AsyncStorage에 의존하고 있습니다.

그 결과, 즉, (사용할 때에도)onAuthStateChanged위의 답변에서 설명한 바와 같이)getAuth().currentUser항상 그럴 것입니다.null앱을 닫았다가 다시 연 후.

문제는 https://github.com/firebase/firebase-js-sdk/pull/7128 에서 자세히 설명합니다.

  // 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*/}

이를 위한 최선의 방법은 약속을 사용하고 응답 후에만 라우터를 인스턴스화하는 것입니다. 이는 다음과 같습니다.

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')
})

내부의다음과 같이 약속을 지킬 수 있는 곳이 바로 Auth Action입니다.

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 - 저에게 이 해결책의 원천입니다.

사용자가 인증된 경우에만 특정 페이지에 액세스하고 인증되지 않은 경우 홈 페이지로 리디렉션하려면 다음 코드가 도움이 될 수 있습니다.

반응: 다음 코드로 구성 요소를 만듭니다.

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} />

in 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().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를 가져옵니다.

화력 기지auth().currentUser.uid

언급URL : https://stackoverflow.com/questions/37883981/cant-get-currentuser-on-load

반응형