在 Next.js 中创建一个 HOC(高阶组件)进行身份验证

Posted

技术标签:

【中文标题】在 Next.js 中创建一个 HOC(高阶组件)进行身份验证【英文标题】:Create a HOC (higher order component) for authentication in Next.js 【发布时间】:2021-05-20 22:00:52 【问题描述】:

所以我在 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;

如果您对如何使用 cookie 在 Next.js 中处理身份验证有任何其他想法,我将不胜感激,因为我是服务器端渲染 react/auth 的新手。

【问题讨论】:

【参考方案1】:

您应该将身份验证逻辑从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
    

然后您可以通过包装getServerSideProps 函数在您的页面中使用它。

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

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

【讨论】:

好的,我的 req.headers 中什至没有 cookie 对象,我只是开始一个新线程,因为我不确定这是否与您的答案有关,但非常感谢您的帮助! @deadcoder0904 将gssp 输入为requireAuthentication(gssp: GetServerSideProps) 对我有用。关于您遇到的错误,您可能需要为此创建一个新问题,因为我认为它与此问题无关。 @deadcoder0904 您可能想为您遇到的打字问题创建一个新问题。 @juliomalves 我会的,但这不是什么大问题。现在使用any :) 有道理-谢谢!!【参考方案2】:

根据 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 

【讨论】:

以上是关于在 Next.js 中创建一个 HOC(高阶组件)进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

React: 高阶组件(HOC)

酶测试认证高阶组件(HOC)

HOC — react高阶组件

React HOC(高阶组件)

如何在 Angular 高阶组件 (HOC) 中将 html 元素作为子元素传递?

如何从 Next.js 中的服务器获取 HOC 中的数据?