Google Data API:如何为桌面应用程序进行身份验证
我在想,如何在桌面应用程序中最简单地进行Google数据API的用户认证。
我看了一下文档,发现我可以选择ClientLogin或者OAuth。
对于ClientLogin,我需要自己实现登录界面和密码输入框(还有保存这些信息的功能等)。我真的很想知道,是否有一些现成的支持,可以弹出一个默认的登录界面,并使用操作系统的钥匙串来存储密码等等。我在想,为什么没有这样的支持呢?这不是应该是标准流程吗?如果把这些实现留给开发者(当然,留给开发者的可能性是好的),我猜很多人可能会想出一些很糟糕的解决方案(当他们只是想快速写个小脚本的时候)。
OAuth似乎是更好的解决方案。不过,似乎有些代码缺失,或者我找到的大部分代码只适用于网页应用。特别是,我跟着文档走,发现这里提到的都是网页应用。在介绍中就提到网页应用。然后我还需要指定一个回调URL,这对桌面应用来说没有意义。我也在想,消费密钥和秘密应该填什么,这对桌面应用来说也不太合理(尤其是开源的)。我查了一下,发现这里(在SO上)说我应该用“anonymous”作为消费密钥和秘密;但在Google文档中哪里有提到呢?用户认证后,我该如何获取令牌呢?
有没有一些示例代码?(不是硬编码的用户名/密码,而是一个可重用的完整认证方法。)
谢谢,
阿尔伯特
到目前为止我的代码:
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
在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 Contacts [ 撤销访问 ]
localhost:58559 — Google Contacts [ 撤销访问 ]
localhost:58815 — Google Contacts [ 撤销访问 ]
localhost:59174 — Google Contacts [ 撤销访问 ]
localhost:58514 — Google Contacts [ 撤销访问 ]
localhost:58533 — Google Contacts [ 撤销访问 ]
localhost:58790 — Google Contacts [ 撤销访问 ]
localhost:59012 — Google Contacts [ 撤销访问 ]
localhost:59191 — Google Contacts [ 撤销访问 ]
我想知道如何避免生成这样的条目。
当我使用xoauth_displayname
时,它会显示那个名字,但仍然会生成多个条目(可能是因为每次的URL大部分不同(因为端口不同))。我该如何避免这种情况?
我现在的代码在Github上。
我还想知道,我应该在哪里、如何以及存储访问令牌和/或请求令牌,以便用户每次启动应用程序时不必一次又一次地被询问。
2 个回答
OAuth也可以在桌面应用程序中使用。对于这样的应用,消费者密钥和秘密“anonymous”是完全合适的。
用户不需要自己进行身份验证。你会从提供者(比如谷歌)那里获取一个令牌,然后用户会授权这个令牌,表示你的应用是一个可信的消费者,这样就可以访问和使用他们的谷歌服务。
这里有一个不错的Python库可以用来实现OAuth:
https://github.com/simplegeo/python-oauth2
这里有一个关于OAuth工作原理的概述:
http://blog.doityourselfandroid.com/2010/11/07/google-oauth-overview/
这里有一个Java的例子,也解释了OAuth认证需要采取的步骤:
http://nilvec.com/implementing-client-side-oauth-on-android/
希望这些信息对你有帮助。