如何在 Next.js 中为 auth 创建 HOC?

How to create HOC for auth in Next.js?

我想创建基本的 Next.js HOC 用于身份验证。我搜了下没弄明白

我的 Next.js 应用程序中有一个管理页面。我想从 http://localhost:4000/user/me 获取 URL return 是我的用户。如果用户数据 returns,组件必须被渲染。如果数据没有 return,我想重定向到 /admin/login 页面。

我试过这段代码,但没有用。我该如何解决这个问题?我也可以使用 useSWR 而不是 fetch 吗?

const withAuth = (Component, { data }) => {
  if (!data) {
    return {
      redirect: {
        destination: "/admin/login",
      },
    };
  }
  return Component;
};

withAuth.getInitialProps = async () => {
  const response = await fetch("http://localhost:4000/user/me");
  const data = await response.json();
  return { data };
};

export default withAuth;
const AdminHome = () => {
  return ();
};
export default withAuth(AdminHome);

服务器端身份验证

根据的回答,您可以为身份验证逻辑创建一个可重用的高阶函数。

如果用户数据不存在,它将重定向到登录页面。否则,该函数将继续调用包装的 getServerSideProps 函数,并将 return 合并的用户数据与页面中生成的 props。

export function withAuth(gssp) {
    return async (context) => {
        const response = await fetch('http://localhost:4000/user/me');
        const data = await response.json();
        
        if (!data) {
            return {
                redirect: {
                    destination: '/admin/login'
                }
            };
        }

        const gsspData = await gssp(context); // Run `getServerSideProps` to get page-specific data
        
        // Pass page-specific props along with user data from `withAuth` to component
        return {
            props: {
                ...gsspData.props,
                data
            }
        };
    }
}

然后您可以在 AdminHome 页面上使用它来包装 getServerSideProps 函数。

const AdminHome = ({ data }) => {
    return ();
};

export const getServerSideProps = withAuth(context => {
    // Your normal `getServerSideProps` code here
    return { props: {} };
});

export default AdminHome;

客户端认证

如果您希望在客户端完成身份验证,您可以创建一个高阶组件来包装您要保护的组件。

const withAuth = (Component) => {
    const AuthenticatedComponent = () => {
        const router = useRouter();
        const [data, setData] = useState()

        useEffect(() => {
            const getUser = async () => {
                const response = await fetch('http://localhost:4000/user/me');
                const userData = await response.json();
                if (!userData) {
                    router.push('/admin/login');
                } else {
                    setData(userData);
                }  
            };
            getUser();
        }, []);

        return !!data ? <Component data={data} /> : null; // Render whatever you want while the authentication occurs
    };

    return AuthenticatedComponent;
};

然后您可以使用它直接包装 AdminHome 组件。

const AdminHome = () => {
  return ();
};

export default withAuth(AdminHome);