You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fastify basic-auth验证时请求体(req.body)始终为空的问题

Fastify中basic-auth验证无法获取req.body的解决方法

问题场景

在Fastify中使用@fastify/basic-auth插件做身份验证,基础功能正常,但验证逻辑里始终无法获取req.body(值一直为空)。需要结合用户名、密码和请求体中的uuid完成验证,只要加入uuid相关判断就报错,去掉则运行正常。

原代码示例

路由文件

fastify.post('/transactions', { schema: schema.createTransactionSchema, onRequest: fastify.basicAuth, }, async (req, rep) => {
  // 路由处理逻辑
})

basic-auth插件文件

import fp from 'fastify-plugin'
import basicAuth from '@fastify/basic-auth'

const plugin = async (fastify, options, done) => {
    const authenticate = { realm: 'api' }

    const validateAuth = async (username, password, req, rep) => {
        console.log(req.body) // 始终为空

        const connection = await fastify.mysql.getConnection()
        let rows = []

        try {
            [rows] = await connection.query(
                `SELECT api_key, secret, uuid
                FROM merchants m
                WHERE m.api_key = :username
                AND m.secret = :password
                AND m.uuid = :uuid
                AND m.state = 1`, { username: username, password: password, uuid: req.body.uuid }
            )
        }
        catch (e) {
            console.log(e)
            throw e
        } finally {
            connection.release()
        } 

        if (rows.length === 0 || username !== rows[0].api_key || password !== rows[0].secret || rows[0].uuid !== req.body.uuid) {
            console.log('hit')
            rep.code(401).send({ message: 'Unauthorized access' })
        }
    }

    fastify.register(basicAuth, { validate: validateAuth, authenticate })

    done()
}

export default fp(plugin)

问题原因

Fastify的钩子执行顺序为:onRequest → preParsing → preValidation → preHandler → 路由处理函数。onRequest钩子在请求刚进入、还未解析请求体时触发,此时req.body还未被填充,自然为空。原代码把fastify.basicAuth放在onRequest阶段,导致验证逻辑无法获取请求体。

解决方案

将身份验证的触发时机从onRequest改为preHandler阶段,该阶段请求体已完成解析,能正常访问req.body。

修改后的代码

路由文件(仅修改钩子阶段)

fastify.post('/transactions', { 
  schema: schema.createTransactionSchema, 
  preHandler: fastify.basicAuth, // 替换onRequest为preHandler
}, async (req, rep) => {
  // 路由处理逻辑
})

插件文件(验证逻辑无需修改,此时req.body可正常获取)

import fp from 'fastify-plugin'
import basicAuth from '@fastify/basic-auth'

const plugin = async (fastify, options, done) => {
    const authenticate = { realm: 'api' }

    const validateAuth = async (username, password, req, rep) => {
        console.log(req.body) // 现在能正常输出请求体内容

        const connection = await fastify.mysql.getConnection()
        let rows = []

        try {
            [rows] = await connection.query(
                `SELECT api_key, secret, uuid
                FROM merchants m
                WHERE m.api_key = :username
                AND m.secret = :password
                AND m.uuid = :uuid
                AND m.state = 1`, 
                { username: username, password: password, uuid: req.body.uuid }
            )
        }
        catch (e) {
            console.log(e)
            throw e
        } finally {
            connection.release()
        } 

        // 推荐使用Fastify内置HTTP错误,更符合框架错误处理流程
        if (rows.length === 0 || username !== rows[0].api_key || password !== rows[0].secret || rows[0].uuid !== req.body.uuid) {
            throw new fastify.httpErrors.Unauthorized('Unauthorized access')
        }
    }

    fastify.register(basicAuth, { validate: validateAuth, authenticate })

    done()
}

export default fp(plugin)

额外注意事项

  1. 确保路由schema正确定义了请求体结构,Fastify会根据schema自动解析请求体,示例schema如下:
const createTransactionSchema = {
  body: {
    type: 'object',
    required: ['uuid'],
    properties: {
      uuid: { type: 'string' }
    }
  }
}
  1. 验证失败时,建议抛出Fastify内置的httpErrors.Unauthorized错误,而非手动调用rep.code().send(),这样能更好地集成Fastify的错误处理机制。

内容的提问来源于stack exchange,提问作者Dally

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 22:15:25