nextjs路由中间件用于认证

nextjs route middleware for authentication

我正在尝试找到一种适当的身份验证方法,我知道这是 GitHub issue page 上的一个敏感主题。

我的认证很简单。我在会话中存储了一个 JWT 令牌。我将它发送到不同的服务器以供批准。如果我返回 true,我们继续前进,如果我返回 false,它会清除会话并将它们发送到主页。

在我的 server.js 文件中,我有以下内容(注意-我使用 nextjs learn 中的示例并仅添加 isAuthenticated):

function isAuthenticated(req, res, next) {
  //checks go here

  //if (req.user.authenticated)
   // return next();

  // IF A USER ISN'T LOGGED IN, THEN REDIRECT THEM SOMEWHERE
  res.redirect('/');
}

server.get('/p/:id', isAuthenticated, (req, res) => {
  const actualPage = '/post'
  const queryParams = { id: req.params.id }
  app.render(req, res, actualPage, queryParams)
})

这按设计工作。如果我刷新页面 /p/123,它将重定向到 /。但是,如果我通过 next/link href 去那里,它不会。我认为这是因为此时它没有使用 express,而是使用 next 的自定义路由。

有没有一种方法可以为每一个 next/link 未通过 express 的人添加支票,以确保用户已登录?

下一次聊天中的蒂姆帮我解决了这个问题。可以找到解决方案 here 但我会引用他的话,以便大家看到:

我还创建了一个 example skeleton template 你可以看看。

--

EDIT July 2021 - WARNING: This is an outdated solution and has not been confirmed to work with the latest versions of next.js. Use skeleton template at your own risk.

NextJS 中没有 API 路由没有 middleware,但是有 HOC,您可以使用它们连接到数据库 - select 用户, ETC: https://hoangvvo.com/blog/nextjs-middleware

随着 Next.js 12 的发布,现在有对使用 Vercel 边缘函数的中间件的 Beta 支持。

https://nextjs.org/blog/next-12#introducing-middleware

Middleware uses a strict runtime that supports standard Web APIs like fetch. > This works out of the box using next start, as well as on Edge platforms like Vercel, which use Edge Functions.

To use Middleware in Next.js, you can create a file pages/_middleware.js. In this example, we use the standard Web API Response (MDN):

// pages/_middleware.js

export function middleware(req, ev) {
  return new Response('Hello, world!')
}

JWT 身份验证示例

next.config.js中:

const withTM = require('@vercel/edge-functions-ui/transpile')()

module.exports = withTM()

pages/_middleware.js中:

import { NextRequest, NextResponse } from 'next/server'
import { setUserCookie } from '@lib/auth'

export function middleware(req: NextRequest) {
  // Add the user token to the response
  return setUserCookie(req, NextResponse.next())
}

pages/api/_middleware.js中:

import type { NextRequest } from 'next/server'
import { nanoid } from 'nanoid'
import { verifyAuth } from '@lib/auth'
import { jsonResponse } from '@lib/utils'

export async function middleware(req: NextRequest) {
  const url = req.nextUrl

  if (url.searchParams.has('edge')) {
    const resOrPayload = await verifyAuth(req)

    return resOrPayload instanceof Response
      ? resOrPayload
      : jsonResponse(200, { nanoid: nanoid(), jwtID: resOrPayload.jti })
  }
}

pages/api/index.js中:

import type { NextApiRequest, NextApiResponse } from 'next'
import { verify, JwtPayload } from 'jsonwebtoken'
import { nanoid } from 'nanoid'
import { USER_TOKEN, JWT_SECRET_KEY } from '@lib/constants'

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== 'GET') {
    return res.status(405).json({
      error: { message: 'Method not allowed' },
    })
  }
  try {
    const token = req.cookies[USER_TOKEN]
    const payload = verify(token, JWT_SECRET_KEY) as JwtPayload
    res.status(200).json({ nanoid: nanoid(), jwtID: payload.jti })
  } catch (err) {
    res.status(401).json({ error: { message: 'Your token has expired.' } })
  }
}