Cor*_*rey 10 python gmail twisted oauth-2.0 google-oauth
我有一个有效的谷歌邮件IMAP客户端,但它最近停止工作.我认为问题是gmail不再允许TTL用户名/密码登录,但现在需要OAuth2.0.
我想知道改变下面示例的最佳方法,以便我的扭曲IMAP客户端使用OAuth2.0进行身份验证.(如果可能的话,没有Google API包就这样做.)
使用用户名/密码登录的示例(不再有效)
class AriSBDGmailImap4Client(imap4.IMAP4Client):
'''
client to fetch and process SBD emails from gmail. the messages
contained in the emails are sent to the AriSBDStationProtocol for
this sbd modem.
'''
def __init__(self, contextFactory=None):
imap4.IMAP4Client.__init__(self, contextFactory)
@defer.inlineCallbacks
def serverGreeting(self, caps):
# log in
try:
# the line below no longer works for gmail
yield self.login(mailuser, mailpass)
try:
yield self.uponAuthentication()
except Exception as e:
uponFail(e, "uponAuthentication")
except Exception as e:
uponFail(e, "logging in")
# done. log out
try:
yield self.logout()
except Exception as e:
uponFail(e, "logging out")
@defer.inlineCallbacks
def uponAuthentication(self):
try:
yield self.select('Inbox')
try:
# read messages, etc, etc
pass
except Exception as e:
uponFail(e, "searching unread")
except Exception as e:
uponFail(e, "selecting inbox")
Run Code Online (Sandbox Code Playgroud)
我有一个琐碎的工厂为这个客户.它通过使用reactor.connectSSL谷歌邮件的主机URL和端口开始.
我已按照https://developers.google.com/gmail/api/quickstart/quickstart-python上的说明查看"已安装的应用"(但我不知道这是否是正确的选择).我可以成功运行他们的"quickstart.py"示例.
我的快速和肮脏的尝试(不起作用)
@defer.inlineCallbacks
def serverGreeting(self, caps):
# log in
try:
#yield self.login(mailuser, mailpass)
flow = yield threads.deferToThread(
oauth2client.client.flow_from_clientsecrets,
filename=CLIENT_SECRET_FILE,
scope=OAUTH_SCOPE)
http = httplib2.Http()
credentials = yield threads.deferToThread( STORAGE.get )
if credentials is None or credentials.invalid:
parser = argparse.ArgumentParser(
parents=[oauth2client.tools.argparser])
flags = yield threads.deferToThread( parser.parse_args )
credentials = yield threads.deferToThread(
oauth2client.tools.run_flow,
flow=flow,
storage=STORAGE,
flags=flags, http=http)
http = yield threads.deferToThread(
credentials.authorize, http)
gmail_service = yield threads.deferToThread(
apiclient.discovery.build,
serviceName='gmail',
version='v1',
http=http)
self.state = 'auth'
try:
yield self.uponAuthentication()
except Exception as e:
uponFail(e, "uponAuthentication")
except Exception as e:
uponFail(e, "logging in")
# done. log out
try:
yield self.logout()
except Exception as e:
uponFail(e, "logging out")
Run Code Online (Sandbox Code Playgroud)
我基本上只是复制了"quickstart.py" serverGreeting,然后尝试将客户端状态设置为"auth".
这种验证很好,但是后来扭曲无法选择收件箱:
[AriSBDGmailImap4Client(TLSMemoryBIOProtocol),客户端]失败:未知命令{random gibberish}
随机乱码具有字母和数字,并且每次选择收件箱命令失败时都是不同的.
谢谢你的帮助!
Cor*_*rey 14
经过大量的阅读和测试,我终于能够使用OAuth2实现对gmail的工作登录.
一个重要的说明是,使用"服务帐户"二步法工艺也不要为我工作.我仍然不清楚为什么这个过程无法使用,但服务帐户似乎无法访问同一帐户中的Gmail.即使服务帐户具有"可以编辑"权限并且启用了Gmail API,也是如此.
有用的参考资料
使用OAuth2的概述https://developers.google.com/identity/protocols/OAuth2
将OAuth2与"已安装的应用程序"一起使用的指南 https://developers.google.com/identity/protocols/OAuth2InstalledApp
设置帐户以将OAuth2与"已安装的应用程序"一起使用的指南 https://developers.google.com/api-client-library/python/auth/installed-app
没有完整Google API的OAuth2例程集合 https://code.google.com/p/google-mail-oauth2-tools/wiki/OAuth2DotPyRunThrough
第1步 - 获取Google客户端ID
使用Gmail帐户登录到https://console.developers.google.com/
启动项目,启用Gmail API并为已安装的应用程序创建新的客户端ID.有关说明,请访问https://developers.google.com/api-client-library/python/auth/installed-app#creatingcred
单击"下载JSON"按钮并将此文件保存在公共区域无法访问的位置(因此可能不在代码存储库中).
第2步 - 获取Google OAuth2 Python工具
从https://code.google.com/p/google-mail-oauth2-tools/wiki/OAuth2DotPyRunThrough下载oauth2.py脚本
第3步 - 获取授权URL
使用步骤2中的脚本获取允许您授权Google项目的URL.
在终端:
python oauth2.py --user={myaccount@gmail.com} --client_id={your client_id from the json file} --client_secret={your client_secret from the json file} --generate_oauth2_token
第4步 - 获取授权码
将步骤3中的URL粘贴到浏览器中,然后单击"接受"按钮.
从网页复制代码.
将代码粘贴到终端并按Enter键.您将获得:
To authorize token, visit this url and follow the directions: https://accounts.google.com/o/oauth2/auth?client_id{...}
Enter verification code: {...}
Refresh Token: {...}
Access Token: {...}
Access Token Expiration Seconds: 3600
Run Code Online (Sandbox Code Playgroud)
第5步 - 保存刷新令牌
从终端复制刷新令牌并将其保存在某处.在此示例中,我将其保存为json格式的文本文件,其中包含"Refresh Token"键.但它也可以保存到私人数据库中.
确保公众无法访问刷新令牌!
第6步 - 制作扭曲的身份验证器
以下是OAuth2身份验证器的工作示例.它需要步骤2中的oauth2.py脚本.
import json
import oauth2
from zope.interface import implementer
from twisted.internet import threads
MY_GMAIL = {your gmail address}
REFRESH_TOKEN_SECRET_FILE = {name of your refresh token file from Step 5}
CLIENT_SECRET_FILE = {name of your cliend json file from Step 1}
@implementer(imap4.IClientAuthentication)
class GmailOAuthAuthenticator():
authName = "XOAUTH2"
tokenTimeout = 3300 # 5 mins short of the real timeout (1 hour)
def __init__(self, reactr):
self.token = None
self.reactor = reactr
self.expire = None
@defer.inlineCallbacks
def getToken(self):
if ( (self.token==None) or (self.reactor.seconds() > self.expire) ):
rt = None
with open(REFRESH_TOKEN_SECRET_FILE) as f:
rt = json.load(f)
cl = None
with open(CLIENT_SECRET_FILE) as f:
cl = json.load(f)
self.token = yield threads.deferToThread(
oauth2.RefreshToken,
client_id = cl['installed']['client_id'],
client_secret = cl['installed']['client_secret'],
refresh_token = rt['Refresh Token'] )
self.expire = self.reactor.seconds() + self.tokenTimeout
def getName(self):
return self.authName
def challengeResponse(self, secret, chal):
# we MUST already have the token
# (allow an exception to be thrown if not)
t = self.token['access_token']
ret = oauth2.GenerateOAuth2String(MY_GMAIL, t, False)
return ret
Run Code Online (Sandbox Code Playgroud)
步骤7 - 为协议注册Authenitcator
在IMAP4ClientFactory中:
def buildProtocol(self, addr):
p = self.protocol(self.ctx)
p.factory = self
x = GmailOAuthAuthenticator(self.reactor)
p.registerAuthenticator(x)
return p
Run Code Online (Sandbox Code Playgroud)
步骤8 - 使用访问令牌进行身份验证
而不是使用"登录",获取访问令牌(如有必要),然后使用身份验证.
更改问题中的示例代码:
@defer.inlineCallbacks
def serverGreeting(self, caps):
# log in
try:
# the line below no longer works for gmail
# yield self.login(mailuser, mailpass)
if GmailOAuthAuthenticator.authName in self.authenticators:
yield self.authenticators[AriGmailOAuthAuthenticator.authName].getToken()
yield self.authenticate("")
try:
yield self.uponAuthentication()
except Exception as e:
uponFail(e, "uponAuthentication")
except Exception as e:
uponFail(e, "logging in")
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1385 次 |
| 最近记录: |