【问题标题】:What's the proper way to use Firebase Authentication along with Firestore?将 Firebase 身份验证与 Firestore 一起使用的正确方法是什么?
【发布时间】:2021-07-04 09:02:17
【问题描述】:

大家好 - 我正在使用 Next.js 和 Firebase 构建一个应用程序,这两种技术对我来说都是全新的。这是一个简单的应用程序,用户创建一个帐户并且必须登录。如果用户不创建一个帐户,该应用程序将毫无用处——他们无法进入下一个屏幕,即仪表板。无论如何,当他们登录时,他们就可以创建旅行/度假行程。我将 Firebase Auth 用于身份验证,并将 Firestore(不是实时数据库)用作我的数据库。我的目标是,当用户登录时,用户可以看到他们创建的每个行程,而没有其他人的。它应该是完整的 CRUD。这也是我第一次进行这种身份验证,所以这可能会增加我的困惑。

我知道我的代码不正确,但它确实有效。不断发生的是,用户登录和注销时似乎存在延迟。我已经在本地副本上对此进行了测试。当我注销然后以其他用户身份重新登录时,它告诉我 uid 为空。 1 到 30 分钟后(严重),页面突然加载了我登录时使用的 uid!我读过的所有内容都表明身份验证存在延迟,但除了指出问题之外,我真的找不到解决方案——所以基本上写了一个控制台日志,说明当时谁登录了,然后同样当他们注销时。另外,我观看/阅读了大量教程,所以也许这是我的代码?对于这部代码小说,我提前感到非常抱歉——我会尽我所能组织起来!


这是我的配置信息,所以我将 Firebase 称为火。登录方法是电子邮件和密码,就在身份验证屏幕上捕获该信息而言,一切在 Firebase 中看起来都应该如此。

import firebase from 'firebase';

const firebaseConfig = {
  apiKey: 'AIzaSyB-xEPETXSfjboKe5H0kPUu-ZdRDGfszmA',
  authDomain: "where-to-jess.firebaseapp.com",
  databaseURL: 'https://where-to-jess-default-rtdb.firebaseio.com/',
  projectId: "where-to-jess",
  storageBucket: "where-to-jess.appspot.com",
  messagingSenderId: "914509599583",
  appId: "1:914509599583:web:80cdf3e4090417b0f35cea"
};
try {
  firebase.initializeApp(firebaseConfig);
} catch(err){
  if (!/already exists/.test(err.message)) {
    console.error('Firebase initialization error', err.stack)}
}
const fire = firebase;
export default fire;

当用户创建帐户时,他们也会被添加到我的数据库中的集合“用户”中。我也在使用 React Hooks(第一次)。他们的电子邮件是他们登录的用户名,但我正在数据库中捕获他们的电子邮件。他们也会在创建帐户后立即登录。这部分也有效。

const handleSubmit = (e) => {
    e.preventDefault();

    setPassword('');

    fire.auth().createUserWithEmailAndPassword(userName, password)
    .then(() => {
      fire.firestore().collection('users').doc(fire.auth().currentUser.uid)
      .set({
        firstName: firstName,
        lastName: lastName,
        email: userName
      })
      .catch(error => {
        console.log('user wasn\'t added to db: ', error);
      })
    })
    .catch(error => {
      console.log('user wasn\'t able to create an account: ', error);
    })
    router.push('/users/dashboard')
  };

这是我的登录代码:

const handleLogin = (e) => {
    e.preventDefault();
    
    fire.auth()
      .signInWithEmailAndPassword(username, password)
      .catch((error) => {
        console.log('user wasn\'t able to login: ', error);
      })

    setUsername('')
    setPassword('')
    router.push('/users/dashboard')
  };

现在是有趣的部分!这是我的行程表单提交代码。我在这里想要实现的是将这个新创建的行程附加到他们在“用户”数据库中的 uid。我省略了所有表单内容,因为它超长。这似乎也有效——无论我使用哪个帐户,我都可以在数据库中看到它。

const handleSubmit = (e) => {
    e.preventDefault();
    
    fire.firestore()
    .collection('users').doc(fire.auth().currentUser.uid).collection('itineraries')
    .add({

      //
    })

    .catch(error => {
      console.log('itinerary not added to db ', error)
    })
    router.push('/users/dashboard')
  }

这就是它发生的地方!我怀疑这是因为我在偷工减料,我将在下面解释。此仪表板应仅显示当前登录用户创建的行程。如果当前登录的用户没有创建任何行程,我会收到一个错误,说 uid 为空。所以,我的解决方法是在他们帐户的数据库中手动创建一个假行程(因为我正在测试)并将 tripName 值设为空。这似乎可行,但这就是奇怪的登录/注销事情发生的地方。

export default function Dashboard() {
  const router = useRouter();
  const [itineraries, setItineraries] = useState([]);
  const [loggedIn, setLoggedIn] = useState(false);

  fire.auth()
  .onAuthStateChanged((user) => {
    if (user) {
      console.log(user.email + " is logged in!");
      setLoggedIn(true)
    } else {
      setLoggedIn(false)
      console.log('User is logged out!');
    }
  })

  useEffect(() => {
    const unsubscribe =
    fire.firestore()
    .collection('users').doc(fire.auth().currentUser.uid).collection('itineraries').where('tripName', '!=', 'null')
    .onSnapshot(snap => {
      const itineraries = snap.docs.map(doc => ({
        id: doc.id,
        ...doc.data()
      }));
      setItineraries(itineraries);
      return () => {
        unsubscribe();
      };
    });
  }, []);


  const handleLogout = () => {
    fire.auth()
      .signOut()
    router.push('/')
  };

最后,这是我在 db 上的一条规则。我在阅读规则文档时感到困惑,我觉得我在这里偷工减料。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read
      allow write
    }
  }
}

再次,我真的很抱歉所有这些代码。这是我第一次使用 React Hooks、Next 和 Firebase——所以它是 Firebases 的文档、教程和我自己的代码的混搭。如有任何帮助或建议,我将不胜感激。

【问题讨论】:

    标签: reactjs firebase google-cloud-firestore firebase-authentication firebase-security


    【解决方案1】:

    该规则将允许所有访问当前数据库中的所有文档。你想要这样的东西:

        rules_version = '2';
        service cloud.firestore {
          match /databases/{database}/documents {
            match /users/{user_id}{
               allow read, write: if request.auth != null && request.auth.uid == user_id;
            }
        }
    }
    

    这将只允许经过身份验证的用户访问

    【讨论】:

    • 非常感谢 - 如此基本的事情!这就是我尝试同时学习下一个、firebase 和 hooks 的结果......结合重新排序我上面的代码完全解决了这个问题。我没有将 useEffect 或 onAuthStateChanged 放在正确的位置。
    • Firebase 可能很难上手,我仍然每天都在学习更多。坚持不懈,你的果实终会开花结果:)
    【解决方案2】:

    这是我 100% 的用户错误,但我想分享一下,因为我的一些问题似乎很常见。除了上述 AspiringApollo 的建议外,我的功能完全失灵(正如我所提到的,钩住新手)。上面加上像这样构造我的函数修复了它:

    useEffect(() => {
        const unsubscribe = 
        fire.auth()
        .onAuthStateChanged((user) => {
          if (user) {
            let uid = user.uid
            console.log(user.email + ' is logged in!');
            setLoggedIn(true)
            // all the things you want to do while the user is logged in goes here
          } else {
            setLoggedIn(false)
            console.log('user is logged out!');
          }
          return () => {
            unsubscribe();
          };
        });
      }, []);
    

    仍然愿意接受建议和更多的目光,因为我知道这有点混乱!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-23
      • 2015-01-25
      • 2012-09-20
      • 2020-09-27
      • 1970-01-01
      • 2017-05-10
      • 2021-07-30
      • 2018-07-19
      相关资源
      最近更新 更多