如何在Nuxt项目中为服务端axios请求添加HMAC认证请求头
实现方案
1. 环境变量配置
首先将API服务商提供的密钥存储在服务端专属环境变量中,Nuxt会自动隔离服务端和客户端环境变量,确保密钥不会泄露到前端。
.env文件示例:
# Nuxt3 服务端专属变量,前缀为NUXT_SERVER_ 客户端完全无法访问 NUXT_SERVER_API_SECRET=你的API服务商提供的专属密钥 # 客户端使用的API前缀,走本地服务端代理 NUXT_PUBLIC_API_BASE=/api # 远端API实际地址,仅服务端可访问 NUXT_SERVER_API_TARGET=https://实际的远端API地址
如果是Nuxt2,服务端专属变量使用PRIVATE_前缀即可。
2. 封装服务端专属axios实例
所有访问远端API的请求都通过该实例发起,实例仅在服务端加载,HMAC生成逻辑完全写在服务端代码中,不会出现在客户端打包产物里。
示例代码(存放在Nuxt3的server/utils/axios.ts路径下,Nuxt2存放在服务端中间件对应目录):
import axios from 'axios' import { createHmac } from 'node:crypto' // 生成HMAC签名的逻辑,完全在服务端运行 function generateHmacToken(secret: string, timestamp: number, requestData: any = {}, requestParams: any = {}) { // 拼接规则需要和API服务商要求的规则完全一致,以下为示例,可根据实际要求调整 const signContent = `${timestamp}${JSON.stringify(requestParams)}${JSON.stringify(requestData)}` return createHmac('sha256', secret).update(signContent).digest('hex') } // 创建服务端专用axios实例 const serverAxios = axios.create({ baseURL: process.env.NUXT_SERVER_API_TARGET }) // 添加请求拦截器,自动注入HMAC头和时间戳 serverAxios.interceptors.request.use((config) => { const timestamp = Math.floor(Date.now() / 1000) const hmacToken = generateHmacToken( process.env.NUXT_SERVER_API_SECRET, timestamp, config.data || {}, config.params || {} ) // 注入要求的请求头 config.headers['X-HMAC-TOKEN'] = hmacToken // 时间戳需要同步传给API用于校验 config.headers['X-TIMESTAMP'] = timestamp return config }) export default serverAxios
3. 配置服务端代理路由
客户端不直接访问远端API,所有请求先走Nuxt自身的服务端路由做中转,客户端仅需传递业务参数即可,不需要关心签名逻辑。
Nuxt3 示例(server/api/[...path].ts)
import serverAxios from '~/server/utils/axios' export default defineEventHandler(async (event) => { const path = getRouterParam(event, 'path') const method = getMethod(event) const query = getQuery(event) const body = method !== 'GET' ? await readBody(event) : undefined // 透传客户端请求到远端API const res = await serverAxios({ url: path, method, params: query, data: body }) // 返回远端API的响应给客户端 return res.data })
Nuxt2 示例(serverMiddleware/apiProxy.js)
const serverAxios = require('./utils/axios') module.exports = async function (req, res) { const path = req.url.replace(/^\/api/, '') const method = req.method const query = req.query const body = method !== 'GET' ? req.body : undefined const result = await serverAxios({ url: path, method, params: query, data: body }) res.end(JSON.stringify(result.data)) }
配置完成后客户端调用登录接口,直接请求/api/login,传入邮箱、密码参数即可,完全不需要接触HMAC生成逻辑。
注意事项
- 所有涉及密钥、签名生成的代码必须放在Nuxt的服务端专属目录下(Nuxt3为
server/,Nuxt2为serverMiddleware/对应目录),Nuxt打包时会自动将这部分代码与客户端代码切割,不会输出到前端包中 - 签名用的时间戳必须取服务端当前时间,禁止使用客户端传递的时间,避免签名被篡改或时间校验不通过
- 确保部署Nuxt服务的服务器时间和网络时间同步,避免因时间偏差导致签名校验失败
- 可根据需求给服务端axios添加重试逻辑,遇到超时导致的签名过期场景自动重新生成签名发起请求
- 敏感接口建议加参数校验和频率限制,避免代理接口被恶意滥用
内容的提问来源于stack exchange,提问作者Oğuz Can Sertel
相关产品推荐
相关产品推荐

