Google Calendar API获取授权用户邮箱添加为活动参会者咨询
1. 添加参会者的流程是否正确
这个流程本身是可行的。教师账号创建的活动存储在教师的primary日历下,学生加入时调用events.update接口,往活动的attendees字段追加学生Google账号对应邮箱,系统会自动给参会人发邀请,活动也会同步到学生的Google日历中。唯一要注意的是,这里必须传学生授权时用的真实Google账号邮箱,不能传用户在你站点注册的自定义邮箱,否则邀请会发错,或者出现学生账号匹配失败看不到活动的问题。
2. 是否需要新增权限
你当前只申请了CALENDAR_EVENTS权限,这个权限仅支持操作日历事件,完全没有读取用户账号信息的授权,确实拿不到用户邮箱,必须新增权限走OpenID Connect流程,不需要申请高敏感权限,只要加两个基础scope就行:
openid:OpenID Connect的必填基础标识email:用于获取用户的Google账号邮箱,属于非敏感权限,不需要走谷歌的额外审核流程,用户授权时只会看到「查看你的邮箱地址」的基础提示,不会影响你现有日历功能的授权转化。
之前你调用userinfo接口返回401,本质原因就是授权时没带这两个scope,access_token没有对应用户信息的读取权限,自然会被拦截。
3. PHP SDK 实现方案
你之前拿不到id_token,核心原因是初始化Google_Client时没把openid和email加入scope列表,调整授权配置后,token返回结构里会自动携带id_token字段,不需要自己发额外HTTP请求拉用户信息,直接用SDK自带方法就能解析出邮箱,全程可以复用你现有的Google_Client实例,不需要额外依赖其他服务。
第一步:调整授权scope配置
初始化客户端时,保留原有日历权限,新增两个需要的scope即可:
$client = new Google_Client(); $client->setClientId('你的应用CLIENT_ID'); $client->setClientSecret('你的应用CLIENT_SECRET'); $client->setRedirectUri('你的授权回调地址'); // 保留原有日历事件权限 $client->addScope(Google_Service_Calendar::CALENDAR_EVENTS); // 新增获取邮箱需要的权限 $client->addScope('openid'); $client->addScope('email'); // 其余原有配置(比如access_type、prompt参数等)保持不变即可
第二步:授权回调中解析邮箱
用户授权完成跳回你的回调地址后,按原有逻辑换取token,此时返回的token数组会新增id_token字段,直接调用SDK内置的校验方法就能拿到用户邮箱:
if (isset($_GET['code'])) { // 按原有逻辑用授权码换取token $token = $client->fetchAccessTokenWithAuthCode($_GET['code']); // 解析id_token $payload = $client->verifyIdToken($token['id_token']); if ($payload) { $googleAccountEmail = $payload['email']; // 这就是用户授权用的Google账号邮箱 // 建议额外校验邮箱是否为谷歌验证过的有效邮箱 $emailVerified = $payload['email_verified']; // 把token和对应谷歌邮箱和你站点的用户账号绑定存储即可 } // 后续日历操作逻辑完全不变,设置token后就能正常调用服务 $client->setAccessToken($token); $calendarService = new Google_Service_Calendar($client); }
追加参会人的代码示例
拿到学生的谷歌邮箱后,更新活动添加参会人的逻辑和你原有逻辑一致,参考如下:
// 先拉取要更新的活动详情 $event = $calendarService->events->get('primary', $targetEventId); // 追加当前学生为参会人 $attendeeList = $event->getAttendees() ?: []; $attendeeList[] = ['email' => $studentGoogleEmail]; $event->setAttendees($attendeeList); // 提交更新 $updatedEvent = $calendarService->events->update('primary', $targetEventId, $event);
几个踩坑提醒
- 之前已经完成授权的老用户,需要重新走一次授权流程,换取带新scope的token,老token因为授权时没包含新scope,既不会返回id_token,也没有权限调用用户信息接口
- 不要自己写file_get_contents或者curl去硬调谷歌用户信息接口,id_token支持本地校验,不需要额外发网络请求,稳定性更高,也不会触发接口限流
- 不需要单独实例化Google的Oauth2服务类,所有操作都可以通过你已经在用的Google_Client和Google_Service_Calendar完成,没有额外依赖。
内容的提问来源于stack exchange,提问作者I'm Root James

