使用GAPI对接Google Identity Services时如何获取用户资料
问题核心原因
你拿不到id_token不是scope配置错了,是用错了GIS的授权客户端:
initTokenClient是专门用来获取「仅调用Google API用的access_token」的模式,这个模式设计上就不会返回id_token,哪怕你加了openid profile emailscope也没用。- 你之前尝试调用plus接口失败是正常的,Google Plus API早在2020年就已经全量下线,所有相关请求都会被拒绝。
两种可行解决方案,选一个就行
方案1:走授权码模式拿id_token(官方推荐,无需额外接口调用)
把你现在用的tokenClient换成codeClient走OAuth2授权码流程,授权完成后会直接返回id_token,解码就能拿到姓名、邮箱信息,同时完全兼容你现有的gapi日历接口调用逻辑,改动最小。
修改步骤:
- 去Google Cloud控制台的OAuth2客户端配置页,把你当前页面的完整地址加到「已授权重定向URI」列表里。
- 替换原来的tokenClient初始化逻辑,核心代码参考:
// 替换原来的initTokenClient部分 let codeClient; await new Promise((resolve, reject) => { try { codeClient = google.accounts.oauth2.initCodeClient({ client_id: 'YOUR_CLIENT_ID', scope: 'openid profile email https://www.googleapis.com/auth/calendar.readonly', redirect_uri: window.location.origin + window.location.pathname, callback: async (authResponse) => { if (authResponse.error) return reject(authResponse); // 解析返回的id_token,直接拿用户信息 const payload = JSON.parse(atob(authResponse.id_token.split('.')[1])); // payload.name就是用户姓名,payload.email就是用户邮箱 console.log('用户信息:', payload.name, payload.email); // 用授权码换access_token,自动注入到gapi.client,不影响你原来的日历调用逻辑 const tokenRes = await fetch('https://oauth2.googleapis.com/token', { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: new URLSearchParams({ code: authResponse.code, client_id: 'YOUR_CLIENT_ID', redirect_uri: window.location.origin + window.location.pathname, grant_type: 'authorization_code' }) }); const tokens = await tokenRes.json(); gapi.client.setToken(tokens); resolve(); } }); resolve(); } catch (err) { reject(err); } }); // 原来触发授权的位置,把requestAccessToken替换成requestCode即可 codeClient.requestCode();
- 把你代码里加载plus v1 discovery文档的代码删掉,服务已下线,加载了也没用还会抛错。
方案2:保留现有access_token模式,调用People API拿用户信息
如果你不想改现有授权逻辑,直接用你已经拿到的access_token调用People API拿用户信息即可,不需要id_token。
注意点:
- scope里补充两个API权限:
https://www.googleapis.com/auth/userinfo.profile、https://www.googleapis.com/auth/userinfo.email,不要只写openid对应的短scope。 - 删掉plus相关的加载逻辑,只保留people v1的discovery文档加载。
- 拿到access_token之后调用people/me接口,必须指定personFields参数,否则不会返回有效数据,核心代码参考:
// 授权成功后调用 const userRes = await gapi.client.people.people.get({ resourceName: 'people/me', personFields: 'names,emailAddresses' }); // 姓名:userRes.result.names[0].displayName // 邮箱:userRes.result.emailAddresses[0].value console.log(userRes.result);
额外注意事项
- 前端直接base64解码id_token拿到的用户信息仅适合做页面展示,如果涉及后端鉴权逻辑,必须在服务端校验id_token的签名,避免伪造请求。
- 老版oauth2 v2的userinfo接口已经处于维护状态,新功能不再迭代,优先选上面两种方案。
内容的提问来源于stack exchange,提问作者Jon H
相关产品推荐
相关产品推荐

