如何在Next.js中间件中获取NextAuth会话或令牌?
解决NextAuth在中间件及服务端获取会话/令牌的问题
核心问题分析
你当前的错误在于:getSession() 是 next-auth/react 包中的客户端方法,不能在中间件(服务端环境)中使用,直接传入handler也不符合API要求。下面分场景给出正确实现方式:
第一步:重构Auth配置,抽离可复用的authOptions
首先把NextAuth的配置单独抽离出来,方便在中间件、服务端组件中复用:
api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth" import CredentialsProvider from "next-auth/providers/credentials" import { _AUTH } from "@/app/services/shared/endpoints"; // 单独导出authOptions,供其他服务端场景使用 export const authOptions = { session: { strategy: 'jwt' }, providers: [ CredentialsProvider({ async authorize(credentials, req){ const res = await fetch(_AUTH._AUTH_LOGIN, { method: 'POST', body: JSON.stringify({user:{...credentials}}), headers: { "Content-Type": "application/json" } }) const user = await res.json() return user || null } }) ], pages: { signIn: '/login', }, // 建议在.env中配置NEXTAUTH_SECRET,NextAuth会自动读取,也可手动指定 secret: process.env.NEXTAUTH_SECRET } export const handler = NextAuth(authOptions) export { handler as GET, handler as POST }
场景一:在中间件中获取会话/令牌
有两种常用方式:
方式1:使用getToken直接获取JWT令牌(推荐,适配JWT策略)
从next-auth/jwt导入getToken,传入请求对象和auth配置:
middleware.ts
import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' import { getToken } from 'next-auth/jwt' import { authOptions } from './app/api/auth/[...nextauth]/route' export async function middleware(request: NextRequest) { // 获取JWT令牌(包含会话信息) const token = await getToken({ req: request, secret: authOptions.secret }) // 修正逻辑:如果未登录(无token),重定向到登录页;否则允许访问 if (!token) { return NextResponse.redirect(new URL('/login', request.url)) } // 若已登录,可在这里使用token中的信息做额外校验 console.log('当前用户令牌:', token) return NextResponse.next() } export const config = { matcher: [ '/empresa/mis-empresas', // 保护该路由 ] }
方式2:使用NextAuth自带的withAuth中间件
更简洁的封装方式,直接用NextAuth提供的中间件工具:
middleware.ts
import { withAuth } from "next-auth/middleware" import { NextResponse } from "next/server" export default withAuth( function middleware(request) { // 可通过request.nextauth.token获取令牌信息 console.log('当前用户令牌:', request.nextauth.token) }, { callbacks: { authorized: ({ token }) => { // 验证是否登录:存在令牌则允许访问 return !!token }, }, pages: { signIn: "/login", // 未登录时重定向的登录页 }, } ) export const config = { matcher: ["/empresa/mis-empresas"], }
场景二:在服务端组件中获取会话
使用next-auth/next/server中的getServerSession方法,传入抽离的authOptions:
示例服务端组件(app/empresa/mis-empresas/page.tsx)
import { getServerSession } from "next-auth/next/server" import { redirect } from 'next/navigation' import { authOptions } from "../api/auth/[...nextauth]/route" export default async function MisEmpresasPage() { const session = await getServerSession(authOptions) // 若未登录,直接重定向到登录页 if (!session) { redirect('/login') } return ( <div> <h1>我的企业</h1> <p>当前用户信息:{JSON.stringify(session.user)}</p> </div> ) }
关键注意事项
- 必须配置
NEXTAUTH_SECRET:可在.env文件中设置,NextAuth会自动读取,否则getToken和getServerSession会报错。 - 修正条件判断逻辑:原代码中
session !== undefined || session !== null永远为true,因为一个值不可能同时是undefined和null,正确判断未登录应该用!session或session === null。 - 自定义JWT内容:如果需要在令牌中添加更多字段,可以在
authOptions中添加jwt回调,比如:
// 在authOptions中添加 jwt: { async callback({ token, user }) { // 登录时将authorize返回的user字段合并到token中 if (user) { token.user = user } return token } }
内容的提问来源于stack exchange,提问作者J P
相关产品推荐
相关产品推荐

