在Next.js中创建用于身份验证的HOC(高阶组件)

bvn4nwqk  于 9个月前  发布在  其他
关注(0)|答案(3)|浏览(108)

所以我在我的Next.js应用程序中创建了身份验证逻辑。我创建了/api/auth/login页面,在那里我处理请求,如果用户的数据是好的,我创建了一个带有JWT令牌的httpOnly cookie,并将一些数据返回到前端。这部分工作正常,但我需要一些方法来保护某些页面,只有登录的用户才能访问它们,我在为此创建HOC时遇到了问题。
我看到的最好的方法是使用getInitialProps,但在Next.js网站上说我不应该再使用它了,所以我想使用getServerSideProps,但这也不起作用,或者我可能做错了什么。
这是我的HOC代码:(cookie存储在userToken名称下)

import React from 'react';
const jwt = require('jsonwebtoken');

const RequireAuthentication = (WrappedComponent) => {

  return WrappedComponent;
};

export async function getServerSideProps({req,res}) {
  const token = req.cookies.userToken || null;

// no token so i take user  to login page
  if (!token) {
      res.statusCode = 302;
      res.setHeader('Location', '/admin/login')
      return {props: {}}
  } else {
    // we have token so i return nothing without changing location
       return;
     }
}
export default RequireAuthentication;

字符串
如果你有任何其他的想法如何在Next.js中使用cookie处理auth,我将非常感谢帮助,因为我是服务器端渲染react/auth的新手。

ztyzrc3y

ztyzrc3y1#

您应该将身份验证逻辑从getServerSideProps分离并提取到可重用的高阶函数中。
例如,您可以让以下函数接受另一个函数(您的getServerSideProps),如果未设置userToken,则会重定向到您的登录页面。

export function requireAuthentication(gssp) {
    return async (context) => {
        const { req, res } = context;
        const token = req.cookies.userToken;

        if (!token) {
            // Redirect to login page
            return {
                redirect: {
                    destination: '/admin/login',
                    statusCode: 302
                }
            };
        }

        return await gssp(context); // Continue on to call `getServerSideProps` logic
    }
}

字符串
然后,您可以通过 Package getServerSideProps函数在页面中使用它。

// pages/index.js (or some other page)

export const getServerSideProps = requireAuthentication(context => {
    // Your normal `getServerSideProps` code here
})

9cbw7uwe

9cbw7uwe2#

基于Julio的回答,我将其用于iron-session

import { GetServerSidePropsContext } from 'next'
import { withSessionSsr } from '@/utils/index'

export const withAuth = (gssp: any) => {
    return async (context: GetServerSidePropsContext) => {
        const { req } = context
        const user = req.session.user

        if (!user) {
            return {
                redirect: {
                    destination: '/',
                    statusCode: 302,
                },
            }
        }

        return await gssp(context)
    }
}

export const withAuthSsr = (handler: any) => withSessionSsr(withAuth(handler))

字符串
然后我用它像:

export const getServerSideProps = withAuthSsr((context: GetServerSidePropsContext) => {
    return {
        props: {},
    }
})


我的withSessionSsr函数看起来像:

import { GetServerSidePropsContext, GetServerSidePropsResult, NextApiHandler } from 'next'
import { withIronSessionApiRoute, withIronSessionSsr } from 'iron-session/next'
import { IronSessionOptions } from 'iron-session'

const IRON_OPTIONS: IronSessionOptions = {
    cookieName: process.env.IRON_COOKIE_NAME,
    password: process.env.IRON_PASSWORD,
    ttl: 60 * 2,
}

function withSessionRoute(handler: NextApiHandler) {
    return withIronSessionApiRoute(handler, IRON_OPTIONS)
}

// Theses types are compatible with InferGetStaticPropsType https://nextjs.org/docs/basic-features/data-fetching#typescript-use-getstaticprops
function withSessionSsr<P extends { [key: string]: unknown } = { [key: string]: unknown }>(
    handler: (
        context: GetServerSidePropsContext
    ) => GetServerSidePropsResult<P> | Promise<GetServerSidePropsResult<P>>
) {
    return withIronSessionSsr(handler, IRON_OPTIONS)
}

export { withSessionRoute, withSessionSsr }

pw9qyyiw

pw9qyyiw3#

对于任何使用TRPC,并希望使用HOC进行auth逻辑的人,这是我们的方法,请注意我们只创建一次助手:

import type {
  GetServerSidePropsContext,
  NextApiRequest,
  NextApiResponse,
} from "next";
import superjson from "superjson";
import type { DehydratedState } from "@tanstack/query-core";
import { createServerSideHelpers } from "@trpc/react-query/server";
import { appRouter } from "@/server/routers/_app";
import { createContext } from "@/server/context";

// Create a function to instantiate helpers
const createHelpers = async (context: GetServerSidePropsContext) => {
  return createServerSideHelpers({
    router: appRouter,
    ctx: await createContext({
      req: context.req as NextApiRequest,
      res: context.res as NextApiResponse,
    }),
    transformer: superjson,
  });
};
export const withAuth = (
  gssp: (
    context: GetServerSidePropsContext,
    helpers: Awaited<ReturnType<typeof createHelpers>>,
  ) => Promise<{ props: { trpcState: DehydratedState } }>,
) => {
  return async (context: GetServerSidePropsContext) => {
    const helpers = await createHelpers(context);

    const { req } = context;
    const user = await helpers.users.sessionUser.fetch();

    if (!user) {
      return {
        redirect: {
          destination: "/sign-in",
          permanent: false,
        },
      };
    }

    if (req.url?.includes("/admin")) {
      if (!user.admin) {
        return {
          notFound: true,
        };
      }
    }
    return gssp(context, helpers);
  };
};

// USAGE

 export const getServerSideProps = withAuth(async (_context, helpers) => {
  await helpers.campaigns.list.prefetch({});

  return {
    props: {
      trpcState: helpers.dehydrate(),
    },
  };
});

字符串

相关问题