如何使用Google服务账号实现Google Apps Script Web App端点授权并模拟自身身份访问
解决Google Apps Script Web App「仅我」权限下的服务账号访问问题
你的核心问题在于:服务账号无法直接模拟你的个人Google账号访问设置为「仅我」权限的Web App。原因很简单:这类Web App的访问权限严格绑定到你的个人账号身份,服务账号是独立的Google身份实体,既不在「仅我」的权限范围内,也无法被直接授权访问这类仅限个人的资源(Google没有提供给服务账号授予「仅我」Web App权限的途径)。
下面给你两种可行的解决方案,对应不同的需求场景:
方案一:用个人账号OAuth 2.0授权访问(推荐,符合「仅我」权限要求)
既然Web App仅限你个人访问,最直接的方式是通过OAuth 2.0授权码流程,获取你个人账号的访问令牌(AccessToken),再用这个令牌发起请求。
操作步骤:
- 打开和你的GAS项目绑定的Google Cloud Console项目,创建OAuth客户端ID:
- 选择「桌面应用」类型,下载客户端配置文件(
credentials.json)。
- 选择「桌面应用」类型,下载客户端配置文件(
- 使用
google-auth-oauthlib库实现授权流程:
from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request import requests import os import pickle # 定义OAuth范围:GAS Web App需要的范围是https://www.googleapis.com/auth/script.external_request SCOPES = ['https://www.googleapis.com/auth/script.external_request'] WEB_APP_URL = 'https://script.google.com/a/macros/<my_project>/s/<my_script_id>/exec' CREDS_PATH = '/path/to/credentials.json' TOKEN_PATH = 'token.pickle' def get_credentials(): creds = None # 加载已保存的令牌 if os.path.exists(TOKEN_PATH): with open(TOKEN_PATH, 'rb') as token: creds = pickle.load(token) # 无有效令牌时,发起授权流程 if not creds or not creds.valid: if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file(CREDS_PATH, SCOPES) creds = flow.run_local_server(port=0) # 保存令牌供下次使用 with open(TOKEN_PATH, 'wb') as token: pickle.dump(creds, token) return creds # 获取凭证并发起请求 creds = get_credentials() authed_session = requests.Session() authed_session.headers.update({'Authorization': f'Bearer {creds.token}'}) resp = authed_session.get(WEB_APP_URL) print(resp.status_code) print(resp.text)
第一次运行时,会弹出浏览器让你登录个人Google账号授权,之后令牌会被保存,后续无需重复授权。
方案二:调整Web App权限+服务账号授权(不推荐,放宽了权限)
如果你坚持要用服务账号访问,只能先放宽Web App的访问权限:
- 修改GAS Web App的「访问权限」为「任何人,甚至匿名」或者「组织内的任何人」(如果你用的是Workspace账号)。
- 在Web App的代码中添加权限校验:比如检查请求中的服务账号邮箱,只允许特定服务账号访问。
示例修改后的GAS代码:
function doGet(e) { // 获取请求中的身份信息 const userSession = Session.getActiveUser(); const allowedServiceAccount = 'your-service-account@<project-id>.iam.gserviceaccount.com'; // 校验是否是指定服务账号 if (userSession.getEmail() === allowedServiceAccount) { boolResult = isDailyGmailCountLargerThan10() console.log(boolResult) if(boolResult) return ContentService.createTextOutput('Done'); else return ContentService.createTextOutput('Error'); } else { return ContentService.createTextOutput('Unauthorized').setStatusCode(401); } } function isDailyGmailCountLargerThan10(){ intCount = GmailApp.search("newer_than:1d").length; return intCount > 10; }
之后你原来的服务账号请求代码就能正常工作了,但注意这种方式已经不再是「仅我」权限,而是允许指定服务账号访问。
关键误区说明
你尝试用服务账号的ID Token去访问是行不通的,因为:
- ID Token只是证明服务账号的身份,而Web App的「仅我」权限只认可你的个人账号身份。
- 域范围委派(Domain-Wide Delegation)仅适用于Google Workspace域管理员,个人Google账号无法使用该功能来让服务账号模拟个人身份。
内容的提问来源于stack exchange,提问作者Question-er XDD
相关产品推荐
相关产品推荐

