Next.js中如何拦截未登录用户访问受保护页面并跳转至登录页
问题原因
- 执行时机问题:
useEffect会在组件渲染完成后才触发,重定向逻辑执行前页面已经先执行了return的渲染代码,当auth.userInfo为空时读取name属性就会抛出空指针错误 - 原有逻辑错误:判断条件
!auth.userInfo && auth.userInfo.role == 'user'存在逻辑漏洞,当!auth.userInfo为真时auth.userInfo已经是null/undefined,再访问role属性会额外触发报错
解决方案
方案1:组件内直接拦截渲染(快速适配当前代码)
修正后代码如下:
import React, { useEffect } from 'react'; import { useSelector } from 'react-redux'; import { useRouter } from 'next/router'; import dynamic from 'next/dynamic'; const Dashboard = () => { const { auth } = useSelector((state) => state); const router = useRouter(); useEffect(() => { // 修正判断逻辑:未登录 或者 角色不符合时跳转到登录页 if (!auth.userInfo || auth.userInfo.role !== 'admin') { router.push('/admin'); } // 把auth加入依赖数组,状态更新时会重新触发判断 }, [auth, router]); // 渲染前先判断用户信息是否存在,不存在直接返回空/加载态,避免执行后续渲染逻辑 if (!auth.userInfo) { return null; // 也可以返回加载占位组件,比如 <div>加载中...</div> } return <h1>{auth.userInfo.name}</h1>; }; export default dynamic(() => Promise.resolve(Dashboard), { ssr: false });
方案2:封装高阶组件做统一路由守卫(适合多页面复用)
可以把登录判断逻辑封装成高阶组件,所有需要登录权限的页面直接套这个高阶组件即可,不需要每个页面重复写判断逻辑:
// 新建utils/withAuth.js import { useSelector } from 'react-redux'; import { useRouter } from 'next/router'; import { useEffect } from 'react'; export const withAuth = (Component) => { const AuthComponent = (props) => { const { auth } = useSelector((state) => state); const router = useRouter(); useEffect(() => { if (!auth.userInfo || auth.userInfo.role !== 'admin') { router.push('/admin'); } }, [auth, router]); if (!auth.userInfo) { return null; } return <Component {...props} />; }; return AuthComponent; };
使用时直接在仪表盘页面引入包裹即可:
import { withAuth } from '../utils/withAuth'; const Dashboard = () => { const { auth } = useSelector((state) => state); return <h1>{auth.userInfo.name}</h1>; }; export default dynamic(() => Promise.resolve(withAuth(Dashboard)), { ssr: false });
内容的提问来源于stack exchange,提问作者Bishal Chhetri
相关产品推荐
相关产品推荐

