页面每次打开或刷新时均触发Google Sign-in登录请求,该如何解决?
解决Google Calendar API登录持久化问题
我看了你这段Google Sign-in的代码,问题核心在于token没有持久化存储——当前代码里gapi.client.getToken()只在页面会话内存中保存token,刷新页面后就丢失了,所以每次都会重新触发登录流程。下面给你具体的解决思路和修改后的代码:
核心解决思路
1. 把token持久化到浏览器本地存储
当成功获取到授权token后,将它存入localStorage(或sessionStorage,根据你需要的持久化时长选择);页面加载时先从本地存储读取token,再初始化gapi客户端。
2. 优化静默授权逻辑
结合Google Identity Services的静默授权能力,页面加载时优先尝试用本地存储的token恢复会话,失效时再触发静默刷新,最后才弹出登录框。
3. 处理token过期
token有有效期,存储时要同时保存过期时间,每次加载时检查是否过期,避免使用无效token。
修改后的完整代码
<script type="text/javascript"> // 用于Google API认证的凭据 const CLIENT_ID = 'XXX'; const API_KEY = 'YYY'; const DISCOVERY_DOC = 'https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest'; const SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'; // 本地存储的key const TOKEN_STORAGE_KEY = 'google_calendar_token'; const TOKEN_EXPIRY_KEY = 'google_calendar_token_expiry'; let tokenClient; let gapiInited = false; let gisInited = false; function gapiLoaded() { gapi.load('client', initializeGapiClient); } async function initializeGapiClient() { await gapi.client.init({ apiKey: API_KEY, discoveryDocs: [DISCOVERY_DOC], }); // 页面加载时尝试从本地存储恢复token const savedToken = localStorage.getItem(TOKEN_STORAGE_KEY); const savedExpiry = localStorage.getItem(TOKEN_EXPIRY_KEY); if (savedToken && savedExpiry && Date.now() < parseInt(savedExpiry)) { // token有效,设置给gapi客户端 gapi.client.setToken({ access_token: savedToken }); } gapiInited = true; maybeAuthorize(); } function gisLoaded() { tokenClient = google.accounts.oauth2.initTokenClient({ client_id: CLIENT_ID, scope: SCOPES, auto_select: true, // 自动选择已登录的用户 callback: async (resp) => { if (resp.error) { console.error('Authorization failed:', resp); document.getElementById('content').innerText = 'Authorization failed.'; return; } // 存储token和过期时间 const expiryTime = Date.now() + (resp.expires_in * 1000); localStorage.setItem(TOKEN_STORAGE_KEY, resp.access_token); localStorage.setItem(TOKEN_EXPIRY_KEY, expiryTime.toString()); await createAllContent(); }, }); gisInited = true; maybeAuthorize(); } function maybeAuthorize() { if (gapiInited && gisInited) { authorize(); } } function authorize() { const currentToken = gapi.client.getToken(); const savedExpiry = localStorage.getItem(TOKEN_EXPIRY_KEY); if (!currentToken || Date.now() >= parseInt(savedExpiry || 0)) { // 无有效token,尝试静默授权 tokenClient.requestAccessToken({ prompt: '' }); } else { // 已有有效token,直接加载内容 createAllContent(); } } // 创建所有内容 function createAllContent() { // 一些使用Google API(gapi)的功能 } </script> <script async defer src="https://apis.google.com/js/api.js" onload="gapiLoaded()"></script> <script async defer src="https://accounts.google.com/gsi/client" onload="gisLoaded()"></script>
关键修改点说明
- token持久化:在授权成功的callback里,把token和过期时间存入
localStorage,页面初始化时读取并验证有效性 - 自动登录配置:给
initTokenClient加上auto_select: true,让GIS自动检测已登录的用户 - 过期检查:每次授权前检查token是否过期,避免使用失效的token触发API错误
这样修改后,用户登录一次后,刷新页面就会自动恢复会话,不需要重复登录了。
内容的提问来源于stack exchange,提问作者Slava
相关产品推荐
相关产品推荐

