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

Google Calendar API服务账号认证失败,旧认证库弃用求助解决方案

解决方案:迁移到Google Identity Services + 实现无登录操作Google Calendar

一、解决弃用错误:替换旧Auth2库为Google Identity Services(GIS)

你收到的错误源于使用了已弃用的gapi.auth2库,必须迁移到Google Identity Services。以下是修改后的前端代码,适配新的授权流程:

<!DOCTYPE html>
<html>
<head>
  <title>Google Calendar API with GIS</title>
  <meta charset="utf-8" />
  <!-- 加载GIS库(替换旧的platform.js) -->
  <script src="https://accounts.google.com/gsi/client" async defer></script>
</head>
<body>
  <p>Google Calendar API Demo</p>
  <button id="authorize_button" style="display: none;">授权访问日历</button>
  <div id="content"></div>

  <script>
    // 配置参数
    const CLIENT_ID = "<你的客户端ID>";
    const API_KEY = "<你的API密钥>";
    const DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"];
    const SCOPES = "https://www.googleapis.com/auth/calendar";

    // 初始化API客户端
    function initClient() {
      gapi.client.init({
        apiKey: API_KEY,
        discoveryDocs: DISCOVERY_DOCS,
      }).then(() => {
        // 显示授权按钮并绑定点击事件
        document.getElementById('authorize_button').style.display = 'block';
        document.getElementById('authorize_button').addEventListener('click', handleAuthClick);
      });
    }

    // 新的OAuth2授权流程
    function handleAuthClick() {
      const tokenClient = google.accounts.oauth2.initTokenClient({
        client_id: CLIENT_ID,
        scope: SCOPES,
        callback: (tokenResponse) => {
          if (tokenResponse.error !== undefined) {
            throw tokenResponse;
          }
          // 授权成功后查询事件
          listEvents();
        },
      });

      tokenClient.requestAccessToken({prompt: 'consent'});
    }

    // 日历事件查询逻辑(与原代码一致)
    function listEvents() {
      gapi.client.calendar.events.list({
        calendarId: "primary",
        timeMin: new Date().toISOString(),
        showDeleted: false,
        singleEvents: true,
        maxResults: 10,
        orderBy: "startTime"
      }).then(function(response) {
        var events = response.result.items;
        var content = "";

        if (events.length > 0) {
          for (let i = 0; i < events.length; i++) {
            var event = events[i];
            var start = event.start.dateTime || event.start.date;
            content += `<p>${event.summary} - ${start}</p>`;
          }
        } else {
          content = "<p>No upcoming events found.</p>";
        }
        document.getElementById("content").innerHTML = content;
      });
    }

    // 加载Google API客户端
    gapi.load('client', initClient);
  </script>
</body>
</html>

二、实现访客无需登录的核心需求

前端直接使用OAuth客户端ID的方式必须要求用户登录Google账号(因为要访问用户个人日历)。如果要让访客完全不用登录,必须通过服务账号在后端实现操作,前端仅需调用你的后端接口:

服务账号方案步骤

  1. 创建服务账号:在Google Cloud控制台创建服务账号,下载JSON格式的密钥文件。
  2. 共享日历给服务账号:打开目标日历(比如你自己的日历),将服务账号邮箱添加为日历编辑者/所有者。
  3. 后端实现接口(以Node.js为例):
// 需先安装依赖:npm install googleapis express
const { google } = require('googleapis');
const express = require('express');
const serviceAccount = require('./service-account-key.json'); // 替换为你的密钥文件

const app = express();
app.use(express.json());

// 初始化服务账号认证
const auth = new google.auth.JWT(
  serviceAccount.client_email,
  null,
  serviceAccount.private_key,
  ['https://www.googleapis.com/auth/calendar']
);

const calendar = google.calendar({ version: 'v3', auth });

// 查询日历事件接口
app.get('/api/calendar/events', async (req, res) => {
  try {
    const resData = await calendar.events.list({
      calendarId: '<目标日历ID>', // 替换为共享给服务账号的日历ID
      timeMin: new Date().toISOString(),
      maxResults: 10,
      singleEvents: true,
      orderBy: 'startTime',
    });
    res.json(resData.data.items);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// 创建日历事件接口
app.post('/api/calendar/events', async (req, res) => {
  const event = {
    summary: req.body.title,
    start: {
      dateTime: req.body.startTime,
      timeZone: 'Asia/Shanghai',
    },
    end: {
      dateTime: req.body.endTime,
      timeZone: 'Asia/Shanghai',
    },
  };

  try {
    const resData = await calendar.events.insert({
      calendarId: '<目标日历ID>',
      resource: event,
    });
    res.json(resData.data);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.listen(3000, () => console.log('后端服务运行在3000端口'));
  1. 前端调用后端接口:
// 查询事件示例
async function fetchEvents() {
  const response = await fetch('/api/calendar/events');
  const events = await response.json();
  
  let content = '';
  if (events.length > 0) {
    events.forEach(event => {
      const start = event.start.dateTime || event.start.date;
      content += `<p>${event.summary} - ${start}</p>`;
    });
  } else {
    content = '<p>No upcoming events found.</p>';
  }
  document.getElementById('content').innerHTML = content;
}

// 页面加载时自动查询
window.onload = fetchEvents;

三、注意事项

  • 原代码中apiKey: "<MY-API-KEY"存在语法错误,缺少闭合引号,需修正为apiKey: "<MY-API-KEY>"。
  • 服务账号仅能访问已共享给它的日历,无法访问未授权的用户个人日历。
  • 如果需求是让访客操作自己的日历,必须使用GIS授权流程(即第一个方案),无法绕开用户登录。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 23:40:34