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

Firebase+TypeScript服务端报错:Auth类型无toJSON属性及Google登录问题

解决Firebase Admin + TypeScript中"Property 'toJSON' does not exist on type 'Auth'"错误及完整Google登录流程

错误原因

你代码里的firebase.auth()返回的是Firebase Auth服务实例,不是已登录用户的对象,所以不存在toJSON()方法。要获取登录用户数据,必须先让前端传递Google登录后的ID Token,后端通过Firebase Admin验证token后才能拿到用户真实信息。

完整流程实现步骤

1. 前端传递ID Token到后端

前端完成Google登录后,获取ID Token并在请求中传递:

// 前端示例(React/Vue等)
import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";

const provider = new GoogleAuthProvider();
const auth = getAuth();

signInWithPopup(auth, provider)
  .then(async (result) => {
    const idToken = await result.user.getIdToken();
    // 发送请求到后端,将token放在Authorization头
    await fetch('/api/users/create', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${idToken}`,
        'Content-Type': 'application/json'
      }
    });
  })
  .catch((error) => {
    console.error(error);
  });

2. 后端验证Token并处理用户数据

修正后的Firebase初始化代码

import admin from 'firebase-admin';
import appConfig from '@/AppConfig/app.config';

export const setupFirebase = () => {
  // 避免重复初始化
  if (!admin.apps.length) {
    admin.initializeApp({
      projectId: appConfig.firebaseProjectID,
      // 生产环境必须配置service account密钥
      // credential: admin.credential.cert(require('./service-account-key.json'))
    });
  }
};

export const firebase = admin;

修正后的UserController代码

import { type Response, type NextFunction, type Request } from 'express';
import UserService from './users.service';
import Api from '@/lib/api';
import { firebase } from '@/lib/firebase';

export default class UserController extends Api {
  private readonly userService = new UserService();

  public createUser = async (
    req: Request,
    res: Response,
    next: NextFunction
  ) => {
    try {
      // 提取请求头中的ID Token
      const authHeader = req.headers.authorization;
      if (!authHeader || !authHeader.startsWith('Bearer ')) {
        return res.status(401).json({ message: '未提供有效Token' });
      }
      const idToken = authHeader.split(' ')[1];

      // 验证Token并解码用户信息
      const decodedToken = await firebase.auth().verifyIdToken(idToken);
      const userData = {
        email: decodedToken.email,
        name: decodedToken.name,
        photoUrl: decodedToken.picture
      };

      // 检查用户是否已存在
      const existingUser = await this.userService.findUserByEmail(userData.email);
      if (existingUser) {
        return res.status(200).json({ message: '用户已存在', user: existingUser });
      }

      // 创建新用户记录
      const newUser = await this.userService.createUser(
        userData.name,
        userData.email,
        userData.photoUrl
      );

      // 返回成功响应
      res.status(201).json({ message: '用户创建成功', user: newUser });
    } catch (e) {
      // 处理Token验证失败等特定错误
      if (e instanceof Error && e.message.includes('invalid token')) {
        return res.status(401).json({ message: '无效的Token' });
      }
      next(e);
    }
  };
}

3. Prisma UserService示例

确保你的UserService正确调用Prisma操作数据库:

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export default class UserService {
  async findUserByEmail(email: string) {
    return prisma.user.findUnique({ where: { email } });
  }

  async createUser(name: string, email: string, photoUrl?: string) {
    return prisma.user.create({
      data: {
        name,
        email,
        photoUrl
      }
    });
  }
}

关键注意事项

  • 生产环境必须配置Firebase Admin的service account密钥,不能仅依赖projectId初始化。
  • ID Token默认有效期1小时,前端需在过期前调用getIdToken(true)刷新token。
  • 处理响应时使用return提前终止流程,避免重复发送响应导致错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 02:53:20