首页 > 解决方案 > 如何在单页应用程序 (SPA) 中正确配置 Firebase 身份验证?

问题描述

我很难理解如何在 SPA Web 应用程序中最好地实现 Firebase Auth。我是 SPA 和 Firebase 的新手。

我的应用程序由安全页面和非安全页面组成。非安全页面用于条款和条件、隐私政策和忘记密码等内容。

在我的应用程序代码中,在最高级别,例如/app.js,我正在导入 Firebase Auth 配置模块作为第一个操作顺序。该模块包含以下函数,它监听身份验证的变化并采取相应的行动。

firebase.auth().onAuthStateChanged(user => {
    if (!user) {
        Store.router.navigate("/login"); // <-- this is my problem
    } else {
        // get user data from Cloud Firestore
        // store user data locally
    }
});

这是我的基本路由器:

router.on({
    '/': () => {
        // import module
    },
    '/login': () => {
        // import module
    },
    '/forgot-password': () => {
        // import module
    }
}).resolve();

在我决定使用 Firebase Auth 之前,我的路由器检查了每条路由的身份验证,看起来有点像这样:

router.on({
    '/': () => {
        if (isAuthenticated) {
            // import module
        } else {
           router.navigate("/login")
        }
    },
    '/login': () => {
        if (!isAuthenticated) {
            // import module
        } else {
           router.navigate("/")
        }
    },
    '/forgot-password': () => {
        // import module
    }
}).resolve();

每次使用我的应用程序的 Firebase Auth 版本更改路由时,onAuthStateChanged侦听器都会收到更新,如果用户已注销,它会将它们重定向到/login页面。如果登录,它会从数据库中获取用户的完整配置文件并将其存储在本地。

现在,除非用户已注销、在/login页面上并想要访问该/forgot-password页面,否则这将非常有效。当用户导航到此页面或任何其他不安全的公共页面时,身份验证侦听器会自行更新并将用户/login立即重定向回,这是错误的。

这是非常不可取的,但我真的很喜欢这个监听器的工作方式,就像/当用户打开多个选项卡并注销一个时,它会将所有选项卡返回到/login.

如何配置此侦听器或重新配置我的应用程序以允许公共页面也可用?我应该退订听众吗?

标签: javascriptfirebaseroutesfirebase-authenticationsingle-page-application

解决方案


我设法解决了这个问题,所以我将在这里与其他人分享我的发现。但是,我确实失去了将所有打开的选项卡从登录页面返回到登录页面的功能,但这对于我的具有公共路由的应用程序来说效果更好。

我现在在我的用户模块中有一个名为的方法,getCurrentUser()它现在是onAuthStateChanged可观察对象所在的位置。因为我使用了 'unsubscribe()` 方法,所以我现在可以在需要时调用它,而无需持续观察。

getCurrentUser: () => {
    return new Promise((resolve, reject) => {
        const unsubscribe = firebase.auth().onAuthStateChanged(user => {
            unsubscribe();
            resolve(user);
        }, reject);
    })
}

在我的路由器中,我现在可以通过调用并等待来检查身份验证状态User.getCurrentMethod()

router.on({
    '/': async () => {
        if (await User.getCurrentUser()) {
            // import module
            // load HTML
        } else {
            router.navigate('/login')
        }
    },
    '/login': () => {
        ...
    }

推荐阅读