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

Node.js + Firebase:如何在服务端验证用户是否已认证

问题根源

firebase.auth().currentUser是客户端Firebase SDK专属属性,仅在浏览器/移动端这类有用户会话上下文的环境中有效。服务端Node.js的Firebase Auth实例与客户端会话完全隔离,直接调用这个属性必然返回null。

正确处理方案

1. 客户端需要传递的内容

客户端完成认证后,调用user.getIdToken()获取当前用户的ID令牌,然后在请求服务端时,将令牌放在Authorization请求头中,格式为Bearer <你的ID令牌>。

客户端示例代码:

// 前端获取令牌并发起请求
const user = firebase.auth().currentUser;
if (user) {
  const idToken = await user.getIdToken();
  await fetch('/your-fastify-api', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${idToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ data: 'example' })
  });
}

2. 服务端验证令牌并获取用户信息

服务端需要使用Firebase Admin SDK的auth().verifyIdToken()方法验证令牌合法性,验证通过后即可解码出用户的UID、邮箱等核心信息,也可以进一步调用getUser(uid)获取完整用户记录。

Fastify路由示例

fastify.get('/protected-resource', async (request, reply) => {
  // 提取请求头中的令牌
  const authHeader = request.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return reply.status(401).send({ error: '请提供有效认证令牌' });
  }
  const idToken = authHeader.split(' ')[1];

  try {
    // 验证并解码令牌
    const decodedToken = await firebase.auth().verifyIdToken(idToken);
    // 可选:根据UID获取完整用户信息
    const user = await firebase.auth().getUser(decodedToken.uid);
    
    return {
      status: 'success',
      userInfo: {
        uid: user.uid,
        email: user.email,
        displayName: user.displayName
      }
    };
  } catch (err) {
    return reply.status(401).send({ error: '令牌无效或已过期' });
  }
});

3. 通用优化:Fastify全局认证钩子

为了避免重复编写验证逻辑,可以通过Fastify的preHandler钩子实现全局或局部的身份校验,将用户信息挂载到request对象中供后续路由使用:

// 定义认证钩子
const authHook = async (request, reply) => {
  const authHeader = request.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    reply.status(401);
    throw new Error('未授权访问');
  }
  const idToken = authHeader.split(' ')[1];
  try {
    const decodedToken = await firebase.auth().verifyIdToken(idToken);
    // 将用户信息挂载到request
    request.authUser = decodedToken;
  } catch (err) {
    reply.status(401);
    throw new Error('认证失败');
  }
};

// 给单个路由添加钩子
fastify.get('/private-route', { preHandler: authHook }, async (request) => {
  return { message: `欢迎回来,${request.authUser.email}` };
});

// 给整个插件/路由组添加钩子
fastify.register((instance, opts, done) => {
  instance.addHook('preHandler', authHook);
  instance.get('/group-route-1', async (request) => { /* ... */ });
  instance.post('/group-route-2', async (request) => { /* ... */ });
  done();
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 02:12:56