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

Server-Side Blazor应用对接Google Calendar并发布事件问题求助

Google Calendar 一键同步发布事件整合方案

一、核心流程梳理

先明确一键操作的完整链路:

  • 点击按钮触发Google OAuth 2.0授权流程
  • 授权完成后获取访问令牌与刷新令牌
  • 安全存储令牌(避免重复授权)
  • 调用Google Calendar API创建目标事件

二、重定向问题修复

  1. 确保Google Cloud控制台中,OAuth客户端ID的重定向URI与代码中的回调地址完全一致(包括协议、域名、端口)
  2. 前端授权跳转需使用Google官方授权端点,示例代码:
const CLIENT_ID = '你的客户端ID';
const REDIRECT_URI = '你的回调地址';
const SCOPES = 'https://www.googleapis.com/auth/calendar.events';

function handleAuthClick() {
  const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&scope=${encodeURIComponent(SCOPES)}&response_type=code&access_type=offline&prompt=consent`;
  window.location.href = authUrl;
}
  • access_type=offline 用于获取刷新令牌,支持后续静默刷新
  • prompt=consent 确保每次授权都能获取刷新令牌(避免缓存导致无法获取)

三、访问令牌存储方案

前端测试场景

用localStorage存储令牌,注意XSS风险:

// 回调页面获取授权码后,交换令牌
async function getTokenFromCode(code) {
  const tokenUrl = 'https://oauth2.googleapis.com/token';
  const params = new URLSearchParams({
    code: code,
    client_id: CLIENT_ID,
    client_secret: '你的客户端密钥',
    redirect_uri: REDIRECT_URI,
    grant_type: 'authorization_code'
  });

  const response = await fetch(tokenUrl, {
    method: 'POST',
    body: params
  });
  const tokenData = await response.json();
  
  // 存储令牌
  localStorage.setItem('google_access_token', tokenData.access_token);
  localStorage.setItem('google_refresh_token', tokenData.refresh_token);
  localStorage.setItem('token_expiry', Date.now() + tokenData.expires_in * 1000);
}

生产环境建议

将令牌存储在后端数据库,前端仅持有会话ID,由后端负责令牌的获取、刷新与存储,避免密钥暴露在前端。

四、事件发布逻辑整合

获取有效令牌后,调用Calendar API创建事件:

async function createCalendarEvent() {
  let accessToken = localStorage.getItem('google_access_token');
  const expiry = localStorage.getItem('token_expiry');
  
  // 令牌过期则用刷新令牌更新
  if (Date.now() > expiry) {
    accessToken = await refreshAccessToken();
  }

  const event = {
    summary: '测试同步事件',
    location: '线上会议',
    description: '通过一键同步创建的Google Calendar事件',
    start: {
      dateTime: '2024-06-01T10:00:00+08:00',
      timeZone: 'Asia/Shanghai'
    },
    end: {
      dateTime: '2024-06-01T11:00:00+08:00',
      timeZone: 'Asia/Shanghai'
    }
  };

  const response = await fetch('https://www.googleapis.com/calendar/v3/calendars/primary/events', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(event)
  });

  const result = await response.json();
  if (response.ok) {
    alert('事件发布成功!事件ID:' + result.id);
  } else {
    console.error('发布失败:', result);
    alert('事件发布失败,请检查授权状态');
  }
}

// 刷新令牌函数
async function refreshAccessToken() {
  const refreshToken = localStorage.getItem('google_refresh_token');
  const tokenUrl = 'https://oauth2.googleapis.com/token';
  const params = new URLSearchParams({
    refresh_token: refreshToken,
    client_id: CLIENT_ID,
    client_secret: '你的客户端密钥',
    grant_type: 'refresh_token'
  });

  const response = await fetch(tokenUrl, {
    method: 'POST',
    body: params
  });
  const tokenData = await response.json();
  
  localStorage.setItem('google_access_token', tokenData.access_token);
  localStorage.setItem('token_expiry', Date.now() + tokenData.expires_in * 1000);
  return tokenData.access_token;
}

五、一键按钮整合

将授权与事件发布逻辑串联,实现点击按钮完成全流程:

<button onclick="handleFullSync()">一键同步发布事件</button>

<script>
// 页面加载时检查是否已有有效令牌
window.onload = async function() {
  const accessToken = localStorage.getItem('google_access_token');
  const expiry = localStorage.getItem('token_expiry');
  if (accessToken && Date.now() < expiry) {
    // 已有有效令牌,可直接触发事件发布
  }
};

async function handleFullSync() {
  const accessToken = localStorage.getItem('google_access_token');
  const expiry = localStorage.getItem('token_expiry');
  
  if (accessToken && Date.now() < expiry) {
    // 已有有效令牌,直接发布事件
    await createCalendarEvent();
  } else {
    // 无有效令牌,触发授权流程
    handleAuthClick();
  }
}

// 回调页面处理:获取URL中的code参数,交换令牌后发布事件
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
if (code) {
  await getTokenFromCode(code);
  // 令牌获取成功后自动发布事件
  await createCalendarEvent();
  // 跳回原页面
  window.location.href = '原页面地址';
}
</script>

关键注意事项

  • 前端不要暴露client_secret,生产环境必须通过后端完成令牌交换
  • 权限范围需确保包含https://www.googleapis.com/auth/calendar.events(或按需选择更宽的calendar权限)
  • 测试时需将Google Cloud项目的OAuth同意屏幕状态设置为“外部”,并添加测试用户

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 03:11:23