在独立Python脚本中向Google进行身份验证的正确机制是什么?
我有一些代码,我用它将Gmail联系人的电子邮件地址提取到文本文件中。它是一个在cron作业中运行的简单Python脚本,基于(当前为v2.0.18) 截至本月早些时候,由于谷歌的原因,这一点不再有效。由此产生的错误如下所示:在独立Python脚本中向Google进行身份验证的正确机制是什么?,python,google-oauth,gdata,google-contacts-api,Python,Google Oauth,Gdata,Google Contacts Api,我有一些代码,我用它将Gmail联系人的电子邮件地址提取到文本文件中。它是一个在cron作业中运行的简单Python脚本,基于(当前为v2.0.18) 截至本月早些时候,由于谷歌的原因,这一点不再有效。由此产生的错误如下所示: {'status': 401, 'body': '<?xml version="1.0" encoding="UTF-8"?>\n<errors xmlns="http://schemas.google.com/g/2005">\n <err
{'status': 401, 'body': '<?xml version="1.0" encoding="UTF-8"?>\n<errors xmlns="http://schemas.google.com/g/2005">\n <error>\n <domain>GData</domain>\n <code>required</code>\n <location type="header">Authorization</location>\n <internalReason>Login Required</internalReason>\n </error>\n</errors>\n', 'reason': 'Unauthorized'}
我知道这会发生,并在其他地方处理它(比如AppEngine应用程序),但忘记了我必须转换这个脚本。现在我在这里,我发现我不知道我应该如何使这项工作
我在Google Apps Developer博客或StackOverflow上找到的所有参考资料都表明,解决方案是使用OAuth2Token。但是,这需要来自GoogleAPI控制台的客户机id和客户机机密,该控制台与应用程序绑定。我没有申请表。我只想通过我的脚本进行身份验证
有人能建议在独立脚本中执行此操作的正确方法吗?还是我运气不好,再也没有办法做到这一点了
这是现有联系人代码的核心:
from gdata.contacts.service import ContactsService, ContactsQuery
user = "myuser@gmail.com"
password = "mypassword"
addresses = set()
client = ContactsService(additional_headers={"GData-Version":"2"})
client.ssl = True
client.ClientLogin(user, password)
groups = client.GetGroupsFeed()
for group in groups.entry:
if group.content.text == "System Group: My Contacts":
query = ContactsQuery()
query.max_results = 9999 # large enough that we'll get "everything"
query.group = group.id.text
contacts = client.GetContactsFeed(query.ToUri())
for contact in contacts.entry:
for email in contact.email:
addresses.add(email.address.lower())
break
return addresses
理想情况下,我希望用一些其他机制替换client.ClientLogin()
,这些机制使用gdata保留其余代码。或者,如果gdata不能真正做到这一点,我愿意转换到其他提供类似功能的库
有人能建议在独立脚本中执行此操作的正确方法吗?还是我运气不好,再也没有办法做到这一点了
没有比你现在使用的机制更好的机制了。您必须设置并使用OAuth2,然后重写脚本
为了使其尽可能不受未来影响,您可以切换到最新版本。使用此API,您可以使用,这对于您的用例来说可能更简单
我知道,这不是您希望听到的答案,但我认为这是唯一的答案。使用curl编写shell脚本比使用curl更容易 搞乱格达图书馆。正如预期的那样,我能够完成大部分任务 在脚本之外,根据 完成验证过程后,我获得了4项必需的凭证: 客户端id、客户端密码、访问令牌和刷新令牌。 根据谷歌的文档,访问令牌最终会过期。你可以 通过请求令牌管理器刷新令牌来获取新的访问令牌。 当您这样做时,您显然会得到一个新的访问令牌,但不会得到新的刷新 代币 我将客户端id和密码以及刷新令牌存储在
凭据中
JSON格式的文件。由于访问令牌随时间而变化,因此它存储在access
文件中,也是JSON格式
脚本的重要部分如下所示:
#!/bin/ksh
CLIENT_ID=$(cat ${CREDENTIALS} | jq -r ".client_id")
CLIENT_SECRET=$(cat ${CREDENTIALS} | jq -r ".client_secret")
REFRESH_TOKEN=$(cat ${CREDENTIALS} | jq -r ".refresh_token")
ACCESS_TOKEN=$(cat ${ACCESS} | jq -r ".access_token")
CONTACTS_URL="https://www.google.com/m8/feeds/contacts/default/full?access_token=${ACCESS_TOKEN}&max-results=5000&v=3.0"
ERROR=$(curl --show-error --silent --fail "${CONTACTS_URL}" -o ${CONTACTS_XML} 2>&1)
RESULT=$?
if [[ ${RESULT} -eq 0 ]]
then
cat ${CONTACTS_XML} | grep 'gd:email' | sed 's/^.*address="//g' | sed 's/".*$//g' | tr '[:upper:]' '[:lower:]' | sort | uniq
elif [[ ${RESULT} -eq 22 ]]
then
echo "${ERROR}" | grep -q "401"
if [[ $? -eq 0 ]]
then
TOKEN_URL="https://www.googleapis.com/oauth2/v3/token"
REFRESH_PARAMS="client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&refresh_token=${REFRESH_TOKEN}&grant_type=refresh_token"
ERROR=$(curl --show-error --silent --fail --data "${REFRESH_PARAMS}" ${TOKEN_URL} -o ${REFRESH_JSON})
RESULT=$?
if [[ ${RESULT} -eq 0 ]]
then
ACCESS_TOKEN=$(cat ${REFRESH_JSON} | jq -r ".access_token")
jq -n --arg access_token "${ACCESS_TOKEN}" '{"access_token": $access_token, }' > ${ACCESS}
CONTACTS_URL="https://www.google.com/m8/feeds/contacts/default/full?access_token=${ACCESS_TOKEN}&max-results=5000&v=3.0"
ERROR=$(curl --show-error --silent --fail "${CONTACTS_URL}" -o ${CONTACTS_XML} 2>&1)
RESULT=$?
if [[ ${RESULT} -eq 0 ]]
then
cat ${CONTACTS_XML} | grep 'gd:email' | sed 's/^.*address="//g' | sed 's/".*$//g' | tr '[:upper:]' '[:lower:]' | sort | uniq
else
print "Unexpected error: ${ERROR}" >&2
exit 1
fi
else
print "Unexpected error: ${ERROR}" >&2
exit 1
fi
else
print "Unexpected error: ${ERROR}" >&2
exit 1
fi
else
print "Unexpected error: ${ERROR}" >&2
exit 1
fi
这并不是世界上最漂亮的东西,但我一直在寻找一些又快又脏的东西,这很管用。哇。令人惊讶的是,一开始如此简单的事情,却在一瞬间变得如此复杂。因为我只需要对联系人进行只读访问,所以看起来OAuth2设备流应该满足我的需要。如果我正确理解了文档,看起来我可以手动执行初始请求和同意,然后在必要时让脚本续订令牌以保持长期访问…?这很好。我将接受这个答案,但我也会在下面的脚本中剪切粘贴,以防对其他人有用。