Next.js 13 App Router中Next-auth与i18n中间件如何结合?
解决Next.js 13 App Router中Next-auth与i18n中间件结合的问题
你的问题核心是同时导出了两个middleware:export { default } from "next-auth/middleware" 和自定义的export function middleware,Next.js只会执行最后定义的那个,导致Next-auth的路由保护逻辑完全失效。另外你写的getLocale函数硬编码了请求头,无法根据用户实际语言偏好匹配,matcher的正则写法也不够严谨。
正确的做法是把认证保护和i18n重定向逻辑合并到同一个middleware中,用Next-auth的withAuth高阶函数包裹自定义逻辑,这样就能同时触发两者的功能。
修正后的完整中间件代码
import { match } from '@formatjs/intl-localematcher' import Negotiator from 'negotiator' import { NextResponse } from 'next/server' import { withAuth } from "next-auth/middleware" const locales = ['en', 'de'] const defaultLocale = 'en' function getLocale(request) { // 动态获取请求头中的语言偏好,替代硬编码值 const acceptLanguage = request.headers.get('accept-language') || defaultLocale const headers = { 'accept-language': acceptLanguage } const languages = new Negotiator({ headers }).languages() return match(languages, locales, defaultLocale) } // 用withAuth包裹自定义middleware:先执行认证检查,再处理i18n逻辑 export default withAuth(function middleware(request) { const pathname = request.nextUrl.pathname // 检查路径是否包含有效locale const pathnameIsMissingLocale = locales.every( (locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}` ) // 无locale时重定向到带locale的路径,处理根路径避免出现//的情况 if (pathnameIsMissingLocale) { const locale = getLocale(request) const targetPath = pathname === '/' ? `/${locale}` : `/${locale}${pathname}` return NextResponse.redirect(new URL(targetPath, request.url)) } }, { // 配置Next-auth的认证规则:仅允许携带有效token的请求访问受保护路由 callbacks: { authorized: ({ token }) => !!token, }, }) export const config = { // 匹配所有非Next.js内部路由,覆盖所有需要i18n处理的路径 matcher: ['/((?!_next).*)'], }
关键说明
withAuth包裹逻辑:Next-auth会先执行认证校验,未登录用户访问/[locale]/user/...路径时,会自动跳转到登录页;通过认证的请求才会进入i18n重定向逻辑。- 修复语言匹配逻辑:从请求头动态获取用户的语言偏好,保证国际化逻辑的准确性。
- 简化matcher规则:用
'/((?!_next).*)'覆盖所有业务路由,不需要单独编写user路由规则,认证逻辑由withAuth的回调处理。 - 根路径兼容:避免重定向时出现
//en这类错误路径。
这样修改后,既能正常处理国际化路由重定向,又能有效保护所有带locale的user路由。
内容的提问来源于stack exchange,提问作者Jon Jampen
相关产品推荐
相关产品推荐

