如何使用Morgan记录Next.js中Next-Auth认证用户信息?
在Next.js/React中结合next-auth与morgan记录认证用户信息
为什么:remote-user无法获取用户信息
:remote-user是morgan针对HTTP基本认证设计的令牌,而next-auth使用Session或JWT认证机制,和HTTP基本认证不兼容,因此无法通过该令牌获取用户信息。
解决方案:自定义请求头 + morgan自定义令牌
方法一:客户端添加请求头,服务器端通过morgan捕获
1. 客户端请求时携带用户信息到请求头
在发送API请求前,通过next-auth的getSession或useSession钩子获取当前用户会话,将非敏感的用户信息(如ID、用户名)添加到请求头中:
import { getSession } from 'next-auth/react'; async function fetchProtectedData() { const session = await getSession(); const response = await fetch('/api/protected-endpoint', { method: 'GET', headers: { // 自定义请求头,建议用X-前缀区分自定义头 'X-User-ID': session?.user?.id || 'anonymous', 'X-Username': session?.user?.name || 'anonymous' } }); const data = await response.json(); // 处理返回数据 }
2. 服务器端配置morgan捕获请求头信息
根据你使用的Next.js路由模式,选择对应的配置方式:
情况1:使用Next.js Middleware(Pages/App Router通用)
创建middleware.js(或middleware.ts)文件,配置morgan自定义令牌并应用到指定路由:
import morgan from 'morgan'; import { NextResponse } from 'next/server'; // 定义morgan自定义令牌,从请求头中提取用户信息 morgan.token('user-id', (req) => req.headers.get('x-user-id') || 'anonymous'); morgan.token('username', (req) => req.headers.get('x-username') || 'anonymous'); // 自定义日志格式 const morganLogger = morgan(':method :url :status :response-time ms - UserID: :user-id | Username: :username'); export function middleware(request) { // 执行morgan日志记录 morganLogger(request, {}, () => {}); return NextResponse.next(); } // 指定需要应用日志中间件的路由(比如所有API路由) export const config = { matcher: ['/api/:path*'], };
情况2:使用自定义Express服务器
如果你的项目使用自定义Express服务器,可直接集成morgan并结合next-auth获取会话:
const express = require('express'); const next = require('next'); const morgan = require('morgan'); const { getServerSession } = require('next-auth/next'); const { authOptions } = require('./pages/api/auth/[...nextauth]'); const dev = process.env.NODE_ENV !== 'production'; const app = next({ dev }); const handle = app.getRequestHandler(); app.prepare().then(() => { const server = express(); // 先通过next-auth获取服务器端会话,挂载到req对象 server.use(async (req, res, next) => { const session = await getServerSession(req, res, authOptions); req.authUser = session?.user; next(); }); // 基于服务器端会话定义morgan令牌 morgan.token('auth-user-id', (req) => req.authUser?.id || 'anonymous'); morgan.token('auth-username', (req) => req.authUser?.name || 'anonymous'); // 配置morgan日志格式 server.use(morgan(':method :url :status :response-time ms - UserID: :auth-user-id | Username: :auth-username')); // 处理所有Next.js路由 server.all('*', (req, res) => { return handle(req, res); }); server.listen(3000, (err) => { if (err) throw err; console.log('> Ready on http://localhost:3000'); }); });
方法二:直接在服务器端通过next-auth获取会话(更安全)
这种方式不需要客户端传递请求头,直接在服务器端通过getServerSession获取用户会话,避免客户端篡改请求头的风险,适合敏感场景。代码示例可参考上面自定义Express服务器中的中间件部分,或在单个API路由中实现:
// pages/api/protected-endpoint.js import { getServerSession } from 'next-auth/next'; import { authOptions } from './auth/[...nextauth]'; import morgan from 'morgan'; // 初始化morgan并自定义令牌 morgan.token('user-id', (req) => req.authUser?.id || 'anonymous'); const logger = morgan(':method :url :status - UserID: :user-id'); export default async function handler(req, res) { // 获取服务器端会话 const session = await getServerSession(req, res, authOptions); req.authUser = session?.user; // 执行日志记录 logger(req, res, () => {}); // 处理API逻辑 res.status(200).json({ data: 'Protected content', user: req.authUser }); }
注意事项
- 不要在请求头中传递敏感信息(如密码、邮箱),只传递用户ID、用户名等非敏感标识。
- Next.js Middleware中的
request是Web Request对象,需用headers.get()获取头信息;Express环境下直接通过req.headers['header-name']访问。 - 若使用App Router,确保
middleware.js放在项目根目录或app目录下。
内容的提问来源于stack exchange,提问作者khteh
相关产品推荐
相关产品推荐

