首页 > 解决方案 > 如何在令牌过期和/或刷新页面后使用 Firebase 在 Next.js 中保持身份验证

问题描述

我正在用 firebase 和 next.js 构建一个应用程序。我在使用 firebase 的身份验证流程时遇到了困难。一切都进展顺利,直到我注意到一个错误/错误。如果我让我的计算机登录到应用程序一段时间并且每当我刷新页面时,似乎两者都会导致我被重定向回我的登录页面。我可以看到为什么刷新会触发我的重定向,因为可能没有足够的时间来及时检查 onAuthStateChange 以const { user } = useAuth()运行,因此在初始页面加载时(刷新后)没有用户。它将进入{ else }导致我此时重定向。但有趣的是,如果我只是单击我的仪表板(受保护的页面)链接,我仍然是经过身份验证的。没有重定向。下面是我的身份验证组件的代码:

AuthComp.js:

import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { useAuth } from "../../context/AuthContext";
function LoadingScreen() {
    return <div className="fixed top-0 right-0 h-screen w-screen z-50 flex justify-center items-center">
        <div className="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-gray-900"></div>
    </div>
}
export function AuthComp(props) {
    const [isAuthenticated, setIsAuthenticated] = useState(false)
    const router = useRouter();
    const { user } = useAuth();
    useEffect(() => {
        let out;
        if (user) {
            setIsAuthenticated(true)
            return () => out ? out() : null
        } else {
            router.push('/auth')
        }
        return () => out;
    }, [user])
    if (!user && (!isAuthenticated)) {
        return <LoadingScreen />;
    }
    return <props.Component user={user} />
};

这是我的身份验证上下文文件的代码:AuthContext.js:

import React, { useState, useEffect, createContext, useContext } from 'react'
import { fbase } from '../utils/auth/firebaseClient'

export const AuthContext = createContext()

export default function AuthProvider({ children }) {
    const [user, setUser] = useState(null)
    const [loadingUser, setLoadingUser] = useState(true) // Helpful, to update the UI accordingly.

    useEffect(() => {
        // Listen authenticated user
        const unsubscriber = fbase.auth.onAuthStateChanged(async (user) => {
            try {
                if (user) {
                    setUser(user);
                } else {
                    setUser(null)
                    return;

                }
            } catch (error) {
                // Most probably a connection error. Handle appropriately.
                console.log('an error occurred', error);
            } finally {
                setLoadingUser(false)
            }
        })

        // Unsubscribe auth listener on unmount
        return () => unsubscriber()
    }, [])

    return (
        <AuthContext.Provider value={{ user, setUser, loadingUser }}>
            {children}
        </AuthContext.Provider>
    )
}

// Custom hook that shorthands the context!
export const useAuth = () => useContext(AuthContext)

标签: javascriptfirebasefirebase-authenticationnext.js

解决方案


可能没有足够的时间及时检查 onAuthStateChange

第一个用户结果onAuthStateChanged绝对不能保证立即发生。您应该期望第一个回调需要一些时间,因为首先加载用户的持久令牌然后验证。

在回调第一次触发之前,您应该为用户假设一个“未知”状态。在第一次回调之前,用户既没有登录也没有退出。我建议在编写应用时考虑到这种三元状态。(相关,firebase.auth().currentUser在页面首次加载时始终为 null。)要了解有关此行为的更多信息,我建议阅读此博客文章


推荐阅读