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 应用程序(即profile
和dashboard
)中为两个页面创建了一个 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,您将获得 <Loader/>
,如果为 false,您将获得下一个三元组;
如果auth
和!user
属性都为真,则AuthLogin
被渲染!
我就是这样做的。我进入了我想要私有的页面并使用了异步函数 getStaticProps 并创建了 prop auth
并将其设置为 true
。
/pages/dashboard.js
Or 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 && !user
时,这就是auth
的来源。
最后两件事:
您需要 MyApp
组件中的 useEffect
函数,并在其依赖项中使用来自钩子的 user
属性。因为这将使URL
在重定向之间保持同步/正确。
在/pages/_app
、MyApp
中添加:
useEffect(() =>
router.replace(router.pathname, undefined, shallow: true )
, [user]);
在AuthLogin
组件中添加:
useEffect(() =>
router.replace('/login', undefined, shallow: true )
, []);
这样可以确保在渲染组件时,URL 是正确的。
我确定如果您的页面经常更改,您将不得不查看getServerSideProps,但这解决了我的静态页面用例!
感谢 Juliomalves 和 Adrian!
【讨论】:
以上是关于Next.js:在实现私有路由时,如何在重定向之前防止未经授权的路由/页面的闪烁?的主要内容,如果未能解决你的问题,请参考以下文章