Next.js:在实现私有路由时,如何在重定向之前防止未经授权的路由/页面的闪烁?

Posted

技术标签:

【中文标题】Next.js:在实现私有路由时,如何在重定向之前防止未经授权的路由/页面的闪烁?【英文标题】:Next.js: How to prevent flash of the Unauthorized route/page prior to redirect when implementing a private route? 【发布时间】:2022-01-14 18:13:44 【问题描述】:

基本上,我在我的 Next.js 应用程序(即profiledashboard)中为两个页面创建了一个 HOC,如果用户未经授权,两个页面将阻止他们访问它们。

示例:pages/profile.js

import withAuth from "../components/AuthCheck/index";

function Profile() 
  return (
    <>
      <h1>Profile</h1>
    </>
  )



export default withAuth(Profile);

我的身份验证组件/HOC:

import  useRouter  from 'next/router'
import  useUser  from '../../lib/hooks'
import  PageLoader  from '../Loader/index'

const withAuth = Component => 
  const Auth = (props) => 
    const  isError  = useUser(); //My hook which is calling /api/user see if there is a user
    const router = useRouter()


    if (isError === 'Unauthorized') 
      if (typeof window !== 'undefined' && router.pathname === '/profile' || router.pathname === 'dashboard') router.push('/login')

      return <PageLoader />
    
    return (
      <Component ...props />
    );

  ;

  if (Component.getInitialProps) 
    Auth.getInitialProps = Component.getInitialProps;
  

  return Auth;
;

export default withAuth;

现在发生的情况是,如果您碰巧在浏览器 URL 栏中输入 /profile/dashboard,在重定向之前您会看到页面一秒钟,即闪烁。

知道为什么会这样吗?

【问题讨论】:

因为重定向发生在客户端 - 在它发生之前,您将首先在服务器上看到生成的页面。防止它的唯一方法是在服务器端重定向。 @juliomalves 很有趣。谢谢。那么你会把这个逻辑放在哪里呢? 我建议通读 Authenticating Server-Rendered Pages 和 Next.js Middleware。 【参考方案1】:

我会考虑在需要验证的页面上使用 getServerSideProps,看看 getServerSideProps 。它会在每个请求的页面上运行服务器端。

或者,在_app 中呈现身份验证组件可能是有意义的(取决于您的项目设置 - 特别是如果您可以访问_app.tsx_ 中的身份验证状态)。更具体地说,您可以将protected:true 属性添加到身份验证墙后面的页面(使用static props)。然后在 app 中,您可以检查特定页面是否已 protected===true 并在用户未通过身份验证时重定向到身份验证组件,例如:

            pageProps.protected && !user ? (
                <LoginComponent />
            ) : (
              <Component ...pageProps />
            )

【讨论】:

感谢阿德里安,您的帖子已解决帮助解决了问题!【参考方案2】:

根据 Juliomalves 和 Adrian 提到的内容,我重新阅读了 Next.js 文档,基于其中包含的内容,总能得到更新。

话虽如此,我尝试了 Adian 发布的内容。

_app.js 文件中,我执行了以下操作:

import dynamic from "next/dynamic";
import  useRouter  from 'next/router'

import  useEffect  from 'react';

import  PageLoader  from '../components/Loader/index'

import  useUser  from '../lib/hooks'

import Login from '../pages/login'

const Layout = dynamic(() => import('../components/Layout'));

function MyApp( Component, pageProps ) 
  const  user, isLoading  = useUser();
  const router = useRouter();

  useEffect(() => 
    router.replace(router.pathname, undefined,  shallow: true )
  , [user])

  function AuthLogin() 
    useEffect(() => 
      router.replace('/login', undefined,  shallow: true )
    , [])
    return <Login />
  

  return (
          <Layout>
            isLoading ? <PageLoader /> :
              pageProps.auth && !user ? (
                <AuthLogin />
              ) : (
                <Component ...pageProps />
              )
            
          </Layout>

  );


export default MyApp

因此,来自 SWR 钩子 useUser()isLoading 属性是第一个条件三元组的一部分,如果为 true,您将获得 &lt;Loader/&gt;,如果为 false,您将获得下一个三元组;

如果auth!user 属性都为真,则AuthLogin 被渲染!

我就是这样做的。我进入了我想要私有的页面并使用了异步函数 getStaticProps 并创建了 prop auth 并将其设置为 true

/pages/dashboard.jsOr whatever you want to be private;

export default function Dashboard() 
  return (
    <>
      <h1>Dashboard</h1>
    </>
  )


export async function getStaticProps() 
  return 
    props: 
      auth: true
    ,
  

所以回到_app.js,当页面被渲染时,getStaticProps 将会,正如文档所说所说:

Next.js 将在构建时使用道具预渲染此页面 由 getStaticProps 返回。

所以当_app 到达pageProps.auth &amp;&amp; !user 时,这就是auth 的来源。

最后两件事:

您需要 MyApp 组件中的 useEffect 函数,并在其依赖项中使用来自钩子的 user 属性。因为这将使URL 在重定向之间保持同步/正确。

/pages/_appMyApp 中添加:

 useEffect(() => 
    router.replace(router.pathname, undefined,  shallow: true )
  , [user]);

AuthLogin组件中添加:

 useEffect(() => 
      router.replace('/login', undefined,  shallow: true )
    , []);

这样可以确保在渲染组件时,URL 是正确的。

我确定如果您的页面经常更改,您将不得不查看getServerSideProps,但这解决了我的静态页面用例!

感谢 Juliomalves 和 Adrian!

【讨论】:

以上是关于Next.js:在实现私有路由时,如何在重定向之前防止未经授权的路由/页面的闪烁?的主要内容,如果未能解决你的问题,请参考以下文章

React js在重定向到新路由后显示通知

如何在重定向时销毁离子组件

Next.js:我们如何将动态路由重定向到静态页面?

在 Firebase onAuthStateChanged 填充状态导致再次登录页面之前重定向到私有路由

Next.js 重定向/验证

为啥 perror() 在重定向时会改变流的方向?