使用Auth0 withMiddlewareAuthRequired致Next.js+Hono API路由CORS问题
问题分析
你在基于子域名的多租户应用中遇到了Auth0中间件与Hono CORS冲突、API路由保护与C兼容问题:
- 当用
withMiddlewareAuthRequired保护所有路由时,Hono API路由触发CORS错误(缺少Access-Control-Allow-Origin头) - 排除API路由后,CORS问题解决但API失去Auth0保护
withApiAuthRequired依赖Node.js原生req/res,无法直接适配Hono的Context对象
核心原因是:Next.js中间件会优先拦截API请求并执行Auth0认证逻辑,此时Hono的CORS中间件还未处理响应头,导致跨域请求失败;同时Auth0的API认证工具与Hono的上下文模型不兼容。
解决方案
方案1:在Next.js中间件中统一处理CORS与API认证
修改middleware.ts,提前为API路由添加CORS头,并针对API请求调整权限校验的响应方式(避免页面重定向):
export default withMiddlewareAuthRequired(async function middleware(request: NextRequest) { const response = NextResponse.next(); const pathname = request.nextUrl.pathname; const host = request.headers.get('host'); const session = await getSession(request, response); // 1. 优先处理API路由的CORS if (pathname.startsWith('/api')) { const origin = request.headers.get('origin'); // 配置允许的源(生产环境替换为你的主域名后缀) const allowedOrigins = process.env.NODE_ENV === 'production' ? [new RegExp(`^https://.*\\.yourdomain\\.com$`)] : [/^http:\/\/.*\.localhost:\d+$/]; if (origin && allowedOrigins.some(regex => regex.test(origin))) { response.headers.set('Access-Control-Allow-Origin', origin); response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization'); response.headers.set('Access-Control-Allow-Credentials', 'true'); } // 处理OPTIONS预检请求 if (request.method === 'OPTIONS') { return new NextResponse(null, { status: 200, headers: response.headers }); } } // 2. 原有子域名逻辑(针对API调整权限校验响应) if (host) { const domain = getDomain(host, true); const segments = host.split('.'); const hasSubdomain = host.includes('localhost') ? segments.length > 1 : segments.length > 2; if (hasSubdomain) { if (pathname === '/') { return NextResponse.redirect( process.env.NODE_ENV === 'production' ? `https://${host}/main` : `http://${host}/main` ); } else if (session && segments[0] !== session.user.org_name) { // API路由返回JSON错误,而非页面重定向 if (pathname.startsWith('/api')) { return new NextResponse(JSON.stringify({ error: 'Unauthorized organization access' }), { status: 401, headers: { ...response.headers, 'Content-Type': 'application/json', }, }); } return NextResponse.redirect( process.env.NODE_ENV === 'production' ? `https://${domain}/error/401/unauthorized_org` : `http://${domain}/error/401/unauthorized_org` ); } } else if (pathname === '/main') { return NextResponse.redirect( process.env.NODE_ENV === 'production' ? `https://${host}` : `http://${host}` ); } } return response; }) export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'], };
关键修改点:
- 提前为API路由注入CORS头,覆盖Auth0中间件的响应头缺失问题
- 针对API请求的权限校验失败,返回JSON格式错误而非页面重定向(符合API响应规范)
- 保留所有路由的Auth0保护,无需排除API路径
方案2:封装适配Hono的Auth0认证中间件
如果希望在Hono层面处理API认证,可以封装一个适配HonoContext的Auth0中间件:
import { createMiddleware } from 'hono/factory'; import { getSession } from '@auth0/nextjs-auth0'; import type { Context } from 'hono'; // 适配Hono的Auth0认证中间件 export const withHonoApiAuthRequired = createMiddleware(async (c: Context, next) => { // 从Hono Context中提取Node.js原生req const req = c.req.raw; // 用NextResponse适配getSession的res参数 const res = new Response(); const session = await getSession(req, res as any); if (!session) { return c.json({ error: 'Unauthorized' }, 401); } // 将session挂载到Hono Context,后续路由可直接调用 c.set('session', session); await next(); });
在Hono路由中使用:
const app = createApp().basePath('/api'); // 移除Hono全局CORS,改用Next.js中间件处理(避免双重CORS冲突) // app.use('*', cors()); // 为需要保护的API路由应用认证中间件 app.use('/organizationFromId/*', withHonoApiAuthRequired); app.get('/organizationFromId/:orgId', async (c) => { const session = c.get('session'); const orgId = c.req.param('orgId'); // 子域名权限校验 const host = c.req.header('host'); if (host) { const segments = host.split('.'); const subdomain = segments[0]; if (subdomain !== session.user.org_name) { return c.json({ error: 'Unauthorized organization access' }, 401); } } // 业务逻辑 return c.json({ orgId, organization: session.user.org_name }); });
优势:
- 完全在Hono生态内处理API认证,逻辑更集中
- 保留Auth0的session校验能力,同时适配Hono的上下文模型
注意事项
- 避免双重CORS处理:要么在Next.js中间件配置CORS,要么在Hono配置,不要同时开启,否则会导致响应头重复或冲突
- API响应规范:API请求失败时不要返回页面重定向,应返回JSON格式的错误信息,避免前端处理异常
- 权限逻辑一致性:确保页面路由和API路由的子域名校验逻辑完全一致,避免出现权限漏洞
内容的提问来源于stack exchange,提问作者user26923635
相关产品推荐
相关产品推荐

