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

Expo(React Native)应用无用户登录调用Google Drive API求助

在Expo(React Native)应用中无需用户登录调用Google Drive API的问题

我是Expo(React Native)开发新手,正在开发一款私有应用,需要访问Google Drive中特定共享文件夹内的文件。已配置具有编辑权限的Google服务账号,并将目标文件夹共享给该账号,当前使用Expo开发构建(非Expo Go)。

希望无需用户登录即可调用Google Drive API,尝试使用google-auth-library编写认证代码,但在浏览器测试时始终报错:"Uncaucht TypeError: prototype may only be an Object or null: undefined",移除相关代码后无报错。Expo官方推荐的@react-native-google-signin/google-signin仅适用于用户登录场景,不符合需求。

当前代码如下:

import Constants from 'expo-constants';
import { GoogleAuth } from 'google-auth-library';
import axios from 'axios';

// 从app.json提取服务账号信息
const {
  GOOGLE_PROJECT_ID,
  GOOGLE_CLIENT_EMAIL,
  GOOGLE_PRIVATE_KEY,
  GOOGLE_PRIVATE_KEY_ID,
  GOOGLE_CLIENT_ID,
} = Constants.expoConfig?.extra || {};

// 修复可能转义的私钥换行符
const privateKeyFormatted = GOOGLE_PRIVATE_KEY.replace(/\\n/g, '\n');

/**
 * 认证并获取Google Drive访问令牌
 * @returns {Promise<string>} 用于API调用的访问令牌
 */
export const authenticateGoogleDrive = async (): Promise<string> => {
  try {
    if (!GOOGLE_CLIENT_EMAIL || !GOOGLE_PRIVATE_KEY || !GOOGLE_PROJECT_ID) {
      throw new Error('Les informations du compte de service sont manquantes');
    }

    console.log("Before GoogleAuth");
    console.log("GOOGLE_CLIENT_EMAIL: ", GOOGLE_CLIENT_EMAIL);
    console.log("privateKeyFormatted: ", privateKeyFormatted);
    console.log("GOOGLE_PROJECT_ID: ", GOOGLE_PROJECT_ID);

    // 创建认证对象
    const auth = new GoogleAuth({
        credentials: {
          type: 'service_account',
          project_id: GOOGLE_PROJECT_ID,
          private_key: privateKeyFormatted,
          client_email: GOOGLE_CLIENT_EMAIL,
        },
        scopes: ['https://www.googleapis.com/auth/drive'],
      });
      
    const client = await auth.getClient();
    const token = await client.getAccessToken();

    if (!token.token) {
      throw new Error('Impossible d’obtenir le jeton d’accès');
    }

    return token.token;
  } catch (error) {
    console.error('Erreur d’authentification Google:', error);
    throw error;
  }
};

问题原因

google-auth-library是为Node.js环境设计的,依赖大量Node.js核心模块(如crypto、fs),无法直接适配React Native/Expo的移动端或浏览器环境,这就是出现原型错误的根本原因。

解决方法:手动生成JWT令牌兑换访问令牌

绕过google-auth-library,基于服务账号信息直接生成JWT令牌,再兑换成Google Drive API的访问令牌,步骤如下:

  1. 安装适配依赖
    使用jsonwebtoken生成JWT,或更适配Expo的expo-jwt:
# 可选:使用jsonwebtoken
npx expo install jsonwebtoken axios

# 或使用expo-jwt(推荐)
npx expo install expo-jwt axios
  1. 替换认证代码
    以下是使用jsonwebtoken的实现(若用expo-jwt,可参考官方文档调整签名逻辑):
import Constants from 'expo-constants';
import jwt from 'jsonwebtoken';
import axios from 'axios';

const {
  GOOGLE_PROJECT_ID,
  GOOGLE_CLIENT_EMAIL,
  GOOGLE_PRIVATE_KEY,
  GOOGLE_PRIVATE_KEY_ID,
} = Constants.expoConfig?.extra || {};

const privateKeyFormatted = GOOGLE_PRIVATE_KEY?.replace(/\\n/g, '\n');

export const authenticateGoogleDrive = async (): Promise<string> => {
  if (!GOOGLE_CLIENT_EMAIL || !privateKeyFormatted || !GOOGLE_PROJECT_ID) {
    throw new Error('服务账号信息不完整');
  }

  // 1. 构建JWT payload
  const now = Math.floor(Date.now() / 1000);
  const payload = {
    iss: GOOGLE_CLIENT_EMAIL,
    scope: 'https://www.googleapis.com/auth/drive',
    aud: 'https://oauth2.googleapis.com/token',
    exp: now + 3600, // 令牌有效期1小时
    iat: now,
  };

  // 2. 签名生成JWT
  const jwtToken = jwt.sign(payload, privateKeyFormatted, {
    algorithm: 'RS256',
    keyid: GOOGLE_PRIVATE_KEY_ID,
  });

  // 3. 兑换成访问令牌
  const response = await axios.post('https://oauth2.googleapis.com/token', {
    grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
    assertion: jwtToken,
  });

  if (!response.data.access_token) {
    throw new Error('无法获取访问令牌');
  }

  return response.data.access_token;
};
  1. 调用Google Drive API示例
    拿到令牌后即可调用API,比如列出目标文件夹内的文件:
export const listDriveFolderFiles = async (folderId: string) => {
  const accessToken = await authenticateGoogleDrive();
  const response = await axios.get('https://www.googleapis.com/drive/v3/files', {
    headers: { Authorization: `Bearer ${accessToken}` },
    params: {
      q: `'${folderId}' in parents`,
      fields: 'files(id,name,mimeType)',
    },
  });
  return response.data.files;
};

注意事项

  • 确保服务账号已被添加到目标Google Drive文件夹的共享列表,权限至少为“查看者”(如需编辑则设为“编辑者”)。
  • 切勿将服务账号私钥硬编码在代码中,始终通过app.json的extra字段配置,并将该文件加入.gitignore避免泄露。
  • 访问令牌有效期为1小时,建议在调用API前检查令牌是否过期,必要时重新生成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:35:21