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



本质上,我在Next.js应用程序中为两个页面(即profiledashboard(创建了一个HOC,两个页面阻止用户在未经授权的情况下访问它们。

示例:pages/profile.js

import withAuth from "../components/AuthCheck/index";
function Profile() {
return (
<>
<h1>Profile</h1>
</>
)
}

export default withAuth(Profile);

我的Auth组件/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和Adrian提到的内容,我根据它们所包含的内容重读了Next.js文档,总是很好地进行刷新。

话虽如此,我还是尝试了阿甸发布的内容。

_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道具都为true,则会渲染AuthLogin

我就是这样做的。我进入我想要的私有页面,使用异步函数getStaticProps,创建道具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 && !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!

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

或者,在_app中呈现身份验证组件可能是有意义的(取决于您的项目设置,尤其是如果您可以访问_app.tsx_中的身份验证状态(。更具体地说,您可以向auth-wall后面的页面添加protected:true道具(使用静态道具(。然后在应用程序中,您可以检查特定页面是否已保护===true,如果用户未通过身份验证,则重定向到身份验证组件,例如:

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

最新更新