如何在令牌过期和/或刷新页面后使用 firebase 在 Next.js 中持久身份验证 [英] How to persist authentication in Next.js using firebase after token expiration and or refreshing the page

查看:67
本文介绍了如何在令牌过期和/或刷新页面后使用 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";函数 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>

}导出函数 AuthComp(props) {const [isAuthenticated, setIsAuthenticated] = useState(false)const 路由器 = useRouter();const { 用户 } = useAuth();useEffect(() => {放出来;如果(用户){setIsAuthenticated(真)返回 () =>出去 ?出():空} 别的 {router.push('/auth')}返回 () =>出去;}, [用户])如果 (!user && (!isAuthenticated)) {返回 <LoadingScreen/>;}return };

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

import React, { useState, useEffect, createContext, useContext } from 'react'从 '../utils/auth/firebaseClient' 导入 { fbase }导出 const AuthContext = createContext()导出默认函数 AuthProvider({ children }) {const [user, setUser] = useState(null)const [loadingUser, setLoadingUser] = useState(true)//有用,相应地更新 UI.useEffect(() => {//监听认证用户const unsubscriber = fbase.auth.onAuthStateChanged(async (user) => {尝试 {如果(用户){设置用户(用户);} 别的 {设置用户(空)返回;}} 捕捉(错误){//很可能是连接错误.妥善处理.console.log('发生错误', 错误);} 最后 {设置加载用户(假)}})//在卸载时取消订阅 auth 监听器返回 () =>退订()}, [])返回 (<AuthContext.Provider value={{ user, setUser, loadingUser }}>{孩子们}</AuthContext.Provider>)}//简写上下文的自定义钩子!export const useAuth = () =>使用上下文(AuthContext)

解决方案

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

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

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

I'm building an app with firebase and next.js. I'm having a hard time with firebase's authentication flows. Everything was coming along well until I noticed a bug/error. If I leave my computer logged in to the app for a while and whenever I refresh the page, It seems like both cause me to be redirected back to my login page. I can see why a refresh would trigger my redirect, as there may not be enough time for the onAuthStateChange to be checked in time for const { user } = useAuth() to run so since there is no user at initial page load (after refresh.) It will go in to the { else } causing me to redirect at this point. But the funny thing is that if I simply click my dashboard (a protected page) link, I'm still authenticated. No redirections. Below is my code for my auth component:

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

Here is my code for my auth context file: 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)

解决方案

there may not be enough time for the onAuthStateChange to be checked in time

The first user result from onAuthStateChanged is definitely not guaranteed to happen immediately. You should expect that the first callback will take some time, as the user's persisted token is first loaded then verified.

Before the callback triggers the first time, you should assume an "unknown" state for the user. The user is neither signed in nor signed out until that first callback. I suggest writing your app with this trinary state in mind. (Related, firebase.auth().currentUser will always be null when a page first loads.) To read more about this behavior, I suggest reading this blog post.

这篇关于如何在令牌过期和/或刷新页面后使用 firebase 在 Next.js 中持久身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆