【问题标题】:Google Data API: how to do authentication for desktop applicationsGoogle Data API:如何对桌面应用程序进行身份验证
【发布时间】: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


我还想知道,我应该将访问令牌和/或请求令牌存储在何处、如何存储以及存储多长时间,以便用户在每次启动应用程序时都不会被一次又一次地询问。

【问题讨论】:

    标签: python gdata-api gdata


    【解决方案1】:

    这是您可以通过您的桌面应用程序从 Google 进行身份验证的方式。 (这就是我的做法) https://developers.google.com/accounts/docs/OAuth2InstalledApp https://developers.google.com/accounts/docs/OAuth2Login

    测试: https://www.googleapis.com/oauth2/v1/userinfo?access_token=ACCESS_TOKEN

    【讨论】:

      【解决方案2】:

      OAuth 也可用于桌面应用程序。消费者密钥和秘密“匿名”非常适合此类应用。

      用户不会验证自己。您将从提供商 (Google) 处获得一个令牌,然后用户将其授权为可信消费者(您的应用)的令牌,通过该令牌可以访问和使用他们的 Google 服务。

      这是一个用于 OAuth 的优秀 Python 库:

      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/

      HTH。

      【讨论】:

      • 用户的授权——这到底是什么样的?如果令牌被授权,我是否打开外部网络浏览器并以某种方式经常重新检查?在示例代码中,我并没有真正看到网络浏览器的打开位置。
      • 另外,gdata 库似乎已经带有 OAuth 功能。所以我想我不需要另一个库吗?或者除了我已经拥有的 gdata 之外,python-oauth2 还提供了什么?
      • 三足 OAuth 的工作方式如下: 1. 您向提供商 (Google) 请求令牌和令牌密钥 2. 您为用户打开一个网络浏览器并将他带到提供商的授权 URL,其中用户可以确认他们愿意授予您访问权限,然后您会收到一个验证码。提供商的站点可以通过提供验证者的 URL 给您回电,或者向用户提供您需要的验证者代码。 3. 使用原始令牌和验证者,您可以从提供者处获得您的最终令牌。
      • 桌面应用程序回调的标准过程是什么?我还没有真正看到关于那个的示例代码(或者没有这样标识它)。在 localhost 上的某个端口上启动一个虚拟 Web 服务器并将其用作回调 URL 是否有意义?给用户一些他必须手动复制和粘贴的代码似乎并不是对用户最友好的选项(我也从未见过)。
      • 这正是您拥有的两个选项。用户要么获得一个代码(实际上是一个 base64 字符串),然后将其提供给你的应用程序,要么你可以启动一个本地网络服务器来捕获来自浏览器的回调 URL。如果您可以注册本地 URL 方案(如在 Android 上),那就更容易了。
      猜你喜欢
      • 1970-01-01
      • 2012-07-25
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-17
      • 2019-05-14
      相关资源
      最近更新 更多