如何在Google Apps Script网页实现15分钟/关标签页自动注销?
实现Google Apps Script网页自动注销(15分钟超时+关闭标签页注销)
问题1:15分钟自动注销的实现
Google Apps Script没有内置的定时注销函数,但可以通过前端定时触发+后端会话超时校验的组合方式实现:
- 前端用定时器监控登录时长,到15分钟时调用后端注销接口
- 后端在会话中存储登录时间,每次请求页面时自动检查是否超时,超时则强制注销
问题2:关闭标签页自动注销的实现
GAS后端无法直接监听浏览器标签页关闭事件,需要通过**前端beforeunload事件+navigator.sendBeacon**实现——普通异步请求在页面卸载时可能被中断,sendBeacon能保证请求稳定发送到服务器。
后端代码修改(Code.gs)
在原有代码基础上增加会话超时校验和登录时间记录:
let MySheets = SpreadsheetApp.getActiveSpreadsheet(); let LoginSheet = MySheets.getSheetByName("Overall"); const SESSION_TIMEOUT_MINUTES = 15; // 设定15分钟超时 function doGet(e) { // 新增:处理关闭标签页时的注销请求 if (e.parameter.action === 'logout') { logoutUser(); return ContentService.createTextOutput('Logged out'); } var output = HtmlService.createTemplateFromFile('Login'); const IMAGEID = "10X-Rh5CwfLb46ITf0iC3ebnILULk7nTc"; var sess = getSession(); if (sess.loggedIn) { // 检查会话是否超时,超时则强制注销 if (checkSessionTimeout(sess)) { logoutUser(); sess = { loggedIn: false }; } if (sess.loggedIn) { output = HtmlService.createTemplateFromFile('Main'); } } return output.evaluate().setTitle('Database Page') .addMetaTag('viewport', 'width=device-width, initial-scale=1') .setFaviconUrl(`https://drive.google.com/uc?id=${IMAGEID}&export=download&format=png`); } // 新增:检查会话是否超时 function checkSessionTimeout(session) { if (!session.loginTime) return false; const now = new Date().getTime(); const loginTime = new Date(session.loginTime).getTime(); const timeoutMs = SESSION_TIMEOUT_MINUTES * 60 * 1000; return now - loginTime > timeoutMs; } function setSession(session) { var sId = Session.getTemporaryActiveUserKey(); var uProp = PropertiesService.getUserProperties(); // 登录成功时记录当前时间 if (session.loggedIn && !session.loginTime) { session.loginTime = new Date().toISOString(); } uProp.setProperty(sId, JSON.stringify(session)); } function getSession() { var sId = Session.getTemporaryActiveUserKey(); var uProp = PropertiesService.getUserProperties(); var sData = uProp.getProperty(sId); let session = sData ? JSON.parse(sData) : { loggedIn: false }; // 自动检查超时,超时则注销 if (session.loggedIn && checkSessionTimeout(session)) { logoutUser(); return { loggedIn: false }; } return session; } // 以下原有函数保持不变 function myURL() { return ScriptApp.getService().getUrl(); } function loginUser(pUID, pPassword) { if (loginCheck(pUID, pPassword)) { var sess = getSession(); sess.loggedIn = true; sess.uid = pUID; setSession(sess); return 'success'; } else { return 'failure'; } } function logoutUser() { var sess = getSession(); sess.loggedIn = false; setSession(sess); } function loginCheck(pUID, pPassword) { let LoginPass = false; let ReturnData = LoginSheet.getRange("Af:Af").createTextFinder(pUID).matchEntireCell(true).findAll(); ReturnData.forEach(function (range) { let StartRow = range.getRow(); let TmpPass = LoginSheet.getRange(StartRow, 33).getValue(); if (TmpPass == pPassword) { LoginPass = true; } }); return LoginPass; }
前端代码修改(Main.html)
在页面底部添加脚本,处理定时注销和标签页关闭事件:
<!-- 原有Main.html内容 --> <script> const TIMEOUT_MINUTES = 15; let logoutTimer; // 启动15分钟注销定时器 function startLogoutTimer() { logoutTimer = setTimeout(() => { google.script.run.withSuccessHandler(() => { window.location.href = google.script.run.myURL(); // 跳转到登录页 }).logoutUser(); }, TIMEOUT_MINUTES * 60 * 1000); } // 用户有交互时重置定时器(比如点击、输入) function resetLogoutTimer() { clearTimeout(logoutTimer); startLogoutTimer(); } // 监听用户交互事件 document.addEventListener('click', resetLogoutTimer); document.addEventListener('keydown', resetLogoutTimer); // 页面加载时启动定时器 window.addEventListener('load', startLogoutTimer); // 关闭标签页时触发注销 window.addEventListener('beforeunload', () => { const logoutUrl = `${google.script.run.myURL()}?action=logout`; navigator.sendBeacon(logoutUrl); }); </script>
内容的提问来源于stack exchange,提问作者user30195264
相关产品推荐
相关产品推荐

