【发布时间】:2011-06-24 01:54:56
【问题描述】:
我想知道在桌面应用程序中对 Google Data API 用户进行身份验证的最佳/最简单方法。
我阅读了docs,似乎我的选项是 ClientLogin 或 OAuth。
对于 ClientLogin,看来我必须自己实现登录/密码的 UI(以及相关的事情,例如将其保存在某处等)。我真的想知道那里是否有更多支持可能会弹出一些默认登录/密码屏幕并使用操作系统钥匙串来存储密码等。我想知道为什么没有这样的支持?这不是标准程序吗?通过将实现留给开发人员(当然,将实现留给开发人员的可能性很好),我猜很多人在这里提出了非常丑陋的解决方案(当他们只想编写一个小脚本时) )。
OAuth 似乎是更好的解决方案。但是,似乎缺少一些代码和/或我发现的大多数代码似乎只与 Web 应用程序相关。特别是,我按照文档得到了here。已经在介绍中,它谈到了 Web 应用程序。稍后,我需要指定一个对桌面应用程序没有意义的回调 URL。另外我想知道我应该输入什么消费者密钥/秘密,因为这对于桌面应用程序也没有意义(尤其是对于开源应用程序而言)。我搜索了一下,有人说here (on SO) 我应该使用“匿名”/“匿名”作为消费者密钥/秘密;但它在谷歌文档中的什么地方这么说?以及用户认证后如何获取token?
有一些示例代码吗? (不是使用硬编码的用户名/密码,而是使用可重复使用的完整身份验证方法。)
谢谢, 阿尔伯特
到目前为止我的代码:
import gdata.gauth
import gdata.contacts.client
CONSUMER_KEY = 'anonymous'
CONSUMER_SECRET = 'anonymous'
SCOPES = [ "https://www.google.com/m8/feeds/" ] # contacts
client = gdata.contacts.client.ContactsClient(source='Test app')
import BaseHTTPServer
import SocketServer
Handler = BaseHTTPServer.BaseHTTPRequestHandler
httpd = BaseHTTPServer.HTTPServer(("", 0), Handler)
_,port = httpd.server_address
oauth_callback_url = 'http://localhost:%d/get_access_token' % port
request_token = client.GetOAuthToken(
SCOPES, oauth_callback_url, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)
loginurl = request_token.generate_authorization_url(google_apps_domain=None)
loginurl = str(loginurl)
import webbrowser
webbrowser.open(loginurl)
但是,这不起作用。我收到此错误:
抱歉,您访问的登录页面未使用 Google Apps 的域。请检查网址,然后重试。
我不太明白。当然,我不使用 Google Apps。
啊,那个错误来自google_apps_domain=None in generate_authorization_url。离开它(即只是loginurl = request_token.generate_authorization_url(),它到目前为止有效。
我当前的代码:
import gdata.gauth
import gdata.contacts.client
CONSUMER_KEY = 'anonymous'
CONSUMER_SECRET = 'anonymous'
SCOPES = [ "https://www.google.com/m8/feeds/" ] # contacts
client = gdata.contacts.client.ContactsClient(source='Test app')
import BaseHTTPServer
import SocketServer
httpd_access_token_callback = None
class Handler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
if self.path.startswith("/get_access_token?"):
global httpd_access_token_callback
httpd_access_token_callback = self.path
self.send_response(200)
def log_message(self, format, *args): pass
httpd = BaseHTTPServer.HTTPServer(("", 0), Handler)
_,port = httpd.server_address
oauth_callback_url = 'http://localhost:%d/get_access_token' % port
request_token = client.GetOAuthToken(
SCOPES, oauth_callback_url, CONSUMER_KEY, consumer_secret=CONSUMER_SECRET)
loginurl = request_token.generate_authorization_url()
loginurl = str(loginurl)
print "opening oauth login page ..."
import webbrowser; webbrowser.open(loginurl)
print "waiting for redirect callback ..."
while httpd_access_token_callback == None:
httpd.handle_request()
print "done"
request_token = gdata.gauth.AuthorizeRequestToken(request_token, httpd_access_token_callback)
# Upgrade the token and save in the user's datastore
access_token = client.GetAccessToken(request_token)
client.auth_token = access_token
这将打开带有底部提示的 Google OAuth 页面:
该网站尚未向 Google 注册以建立用于授权请求的安全连接。我们建议您拒绝访问,除非您信任该网站。
但它仍然不起作用。当我尝试访问联系人(即只是一个client.GetContacts())时,我收到此错误:
gdata.client.Unauthorized: Unauthorized - Server responded with: 401, <HTML>
<HEAD>
<TITLE>Token invalid - AuthSub token has wrong scope</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Token invalid - AuthSub token has wrong scope</H1>
<H2>Error 401</H2>
</BODY>
</HTML>
好的,看来我确实设置了错误的范围。当我使用http 而不是https(即SCOPES = [ "http://www.google.com/m8/feeds/" ])时,它可以工作。
但我真的很想使用 https。我想知道我该怎么做。
另外,这个解决方案的另一个问题:
在我的 Google 帐户的授权访问列表中,我现在有一堆这样的 localhost 条目:
localhost:58630 — Google 通讯录 [撤销访问权限]
localhost:58559 — Google 通讯录 [撤销访问]
localhost:58815 — Google 通讯录 [撤销访问]
localhost:59174 — Google 通讯录 [撤销访问]
localhost:58514 — Google 通讯录 [撤销访问]
localhost:58533 — Google 通讯录 [撤销访问]
localhost:58790 — Google 通讯录 [撤销访问]
localhost:59012 — Google 通讯录 [撤销访问]
localhost:59191 — Google 通讯录 [撤销访问]
我想知道我怎样才能避免它会出现这样的条目。
当我使用xoauth_displayname 时,它会显示该名称,但仍会输入多个条目(可能是因为每次 URL 仍然大部分不同(因为端口))。我怎样才能避免这种情况?
我当前的代码现在在Github。
我还想知道,我应该将访问令牌和/或请求令牌存储在何处、如何存储以及存储多长时间,以便用户在每次启动应用程序时都不会被一次又一次地询问。
【问题讨论】: