用于谷歌 API 访问的 Oauth2 似乎依赖于请求 Python 任务的用户 ID
Posted
技术标签:
【中文标题】用于谷歌 API 访问的 Oauth2 似乎依赖于请求 Python 任务的用户 ID【英文标题】:Oauth2 for google API access seems to be dependent on the user-ID of the requesting Python task 【发布时间】:2021-10-01 16:04:04 【问题描述】:我正在重新编写一个需要能够发送和接收电子邮件的程序。旧版本在桌面上独立运行,并使用 SMTP 和 POP3 使用 gmail 帐户代表我发送和接收。没关系,但是最近,很多发送的电子邮件最终都进入了垃圾文件夹。所以,我想要一种更可靠的方式来“代表”用户(我)发送。新版本是一个网络应用程序而不是桌面程序,因此电子邮件活动是在服务器端完成的,我正在尝试使用 Gmail API。
当进程在服务器上运行时,我被困了几天,无法获取 API 访问令牌(“无效令牌”)。这是我所做的:
-
使用 Google Cloud Platform 控制台创建/下载 credentials.json 文件
使用“快速启动”python代码成功测试用户授权,将令牌保存为文件token.json并发送测试消息
将类似的代码合并到我的程序中,但从命令行将其作为测试运行 > 成功!
将整个文件夹复制到我的服务器,并使用 SSH 终端从命令行再次运行它作为测试 > 成功(包括使用刷新令牌)!
将其作为 Web 应用程序 (WSGI Python) 运行,但它失败了。
注意到当它作为网络应用程序运行时任务的所有者不是我,在 SSH 终端上,我将用户更改为“www-data”并重新尝试测试并遇到错误(cred.valid = = 假)之后
creds = Credentials.from_authorized_user_file('token.json', scopes=SCOPES)
结果触发了用户身份验证流程 - 因为它无法远程使用(我相信),所以它停止了。
我已确保两个用户(www-data 和 ben)都可以平等地访问文件夹中的所有文件。谁能给我一个线索,我必须做些什么才能使它与“www-data”用户一起工作?
def get_credentials():
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly','https://www.googleapis.com/auth/gmail.send']
creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
logging("In get_credentials. Python version: " + sys.version )
if os.path.exists('token.json'):
logging("Using token.json")
with open('token.json',"r",encoding="utf-8") as fi:
s = fi.read()
logging( s )
logging( str(os.environ))
creds = Credentials.from_authorized_user_file('token.json', scopes=SCOPES)
logging("Creds " + str(creds))
logging(str(creds.refresh_token) + " " + str( creds.expired) + " " + str( creds.valid))
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
logging("No valid credentials found")
if creds and creds.expired and creds.refresh_token:
logging("Going for a refresh")
creds.refresh(Request())
else:
logging("Going for live authentication flow!")
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(creds.to_json())
logging("Saved token.json")
service = build('gmail', 'v1', credentials=creds)
return service
【问题讨论】:
【参考方案1】:您遇到的问题是您使用的是 InstalledAppFlow。这将导致在运行代码的机器上弹出同意屏幕,然后将刷新令牌和访问令牌存储在 token.json 中。
您可以做的是在本地运行一次以确保创建了 token.json,然后确保在将其上传到服务器时也上传了 token.json。
请记住,除非您的应用程序设置为生产,否则您的刷新令牌只能使用 7 天,因此您需要每周在本地重新授权一次。
【讨论】:
感谢您的快速回答!我确实在本地运行它来创建 token.json 并在上传到服务器时包含该文件。这就是它作为服务器上的命令行测试运行良好的方式。我不认为我可以将申请批准为“生产”,因此 7 天的限制将是一个问题。有更好的方法吗? 测试中的应用程序没有刷新令牌,仅持续 7 天。然后你需要再次授权。以上是关于用于谷歌 API 访问的 Oauth2 似乎依赖于请求 Python 任务的用户 ID的主要内容,如果未能解决你的问题,请参考以下文章
重复使用 Oauth2 凭据来访问 YouTube api [关闭]
oauth2.0授予Web应用访问用户的Google spreadhseets所需的最小范围是多少?
使用 OAuth2 客户端凭据流保护用 PHP 编写的 REST API