您如何从(非网络)python 客户端访问经过身份验证的 Google App Engine 服务?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/101742/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 19:30:00  来源:igfitidea点击:

How do you access an authenticated Google App Engine service from a (non-web) python client?

pythonweb-servicesgoogle-app-engineauthentication

提问by dalelane

I have a Google App Engine app - http://mylovelyapp.appspot.com/It has a page - mylovelypage

我有一个 Google App Engine 应用程序 - http://mylovelyapp.appspot.com/它有一个页面 - mylovelypage

For the moment, the page just does self.response.out.write('OK')

目前,页面只是 self.response.out.write('OK')

If I run the following Python at my computer:

如果我在我的电脑上运行以下 Python:

import urllib2
f = urllib2.urlopen("http://mylovelyapp.appspot.com/mylovelypage")
s = f.read()
print s
f.close()

it prints "OK"

它打印“OK”

the problem is if I add login:requiredto this page in the app's yaml

问题是如果我login:required在应用程序的 yaml 中添加到此页面

then this prints out the HTML of the Google Accounts login page

然后这会打印出 Google 帐户登录页面的 HTML

I've tried "normal" authentication approaches. e.g.

我尝试过“正常”的身份验证方法。例如

passman = urllib2.HTTPPasswordMgrWithDefaultRealm()

auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(None,
                          uri='http://mylovelyapp.appspot.com/mylovelypage',
                          user='[email protected]',
                          passwd='billybobspasswd')
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)

But it makes no difference - I still get the login page's HTML back.

但这并没有什么区别——我仍然得到了登录页面的 HTML。

I've tried Google's ClientLogin auth API, but I can't get it to work.

我已经尝试过Google 的 ClientLogin auth API,但我无法让它工作。

h = httplib2.Http()

auth_uri = 'https://www.google.com/accounts/ClientLogin'
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
myrequest = "Email=%s&Passwd=%s&service=ah&source=DALELANE-0.0" % ("[email protected]", "billybobspassword")
response, content = h.request(auth_uri, 'POST', body=myrequest, headers=headers)

if response['status'] == '200':
    authtok = re.search('Auth=(\S*)', content).group(1)

    headers = {}
    headers['Authorization'] = 'GoogleLogin auth=%s' % authtok.strip()
    headers['Content-Length'] = '0'

    response, content = h.request("http://mylovelyapp.appspot.com/mylovelypage", 
                                  'POST', 
                                  body="", 
                                  headers=headers)

    while response['status'] == "302":        
        response, content = h.request(response['location'], 'POST', body="", headers=headers) 

    print content

I do seem to be able to get some token correctly, but attempts to use it in the header when I call 'mylovelypage' still just return me the login page's HTML. :-(

我似乎确实能够正确获取一些令牌,但是当我调用“mylovelypage”时尝试在标题中使用它仍然只是返回登录页面的 HTML。:-(

Can anyone help, please?

请问有人可以帮忙吗?

Could I use the GData client libraryto do this sort of thing? From what I've read, I think it should be able to access App Engine apps, but I haven't been any more successful at getting the authentication working for App Engine stuff there either

我可以使用GData 客户端库来做这种事情吗?从我读到的内容来看,我认为它应该能够访问 App Engine 应用程序,但我在为 App Engine 的东西进行身份验证方面也没有取得更大的成功

Any pointers to samples, articles, or even just keywords I should be searching for to get me started, would be very much appreciated.

任何指向示例、文章或什至只是我应该搜索的关键字以帮助我入门的指针,都将不胜感激。

Thanks!

谢谢!

采纳答案by Nick Johnson

appcfg.py, the tool that uploads data to App Engine has to do exactly this to authenticate itself with the App Engine server. The relevant functionality is abstracted into appengine_rpc.py. In a nutshell, the solution is:

appcfg.py,将数据上传到 App Engine 的工具必须完全做到这一点,以便向 App Engine 服务器进行身份验证。相关功能被抽象到 appengine_rpc.py 中。简而言之,解决方案是:

  1. Use the Google ClientLogin APIto obtain an authentication token. appengine_rpc.py does this in _GetAuthToken
  2. Send the auth token to a special URL on your App Engine app. That page then returns a cookie and a 302 redirect. Ignore the redirect and store the cookie. appcfg.py does this in _GetAuthCookie
  3. Use the returned cookie in all future requests.
  1. 使用Google ClientLogin API获取身份验证令牌。appengine_rpc.py 在_GetAuthToken 中执行此操作
  2. 将身份验证令牌发送到 App Engine 应用程序上的特殊 URL。然后该页面返回一个 cookie 和一个 302 重定向。忽略重定向并存储 cookie。appcfg.py 在_GetAuthCookie 中执行此操作
  3. 在以后的所有请求中使用返回的 cookie。

You may also want to look at _Authenticate, to see how appcfg handles the various return codes from ClientLogin, and _GetOpener, to see how appcfg creates a urllib2 OpenerDirector that doesn't follow HTTP redirects. Or you could, in fact, just use the AbstractRpcServer and HttpRpcServer classes wholesale, since they do pretty much everything you need.

您可能还想查看_Authenticate,了解 appcfg 如何处理来自 ClientLogin 的各种返回代码,以及_GetOpener,了解 appcfg 如何创建不遵循 HTTP 重定向的 urllib2 OpenerDirector。或者,事实上,您可以只批发使用 AbstractRpcServer 和 HttpRpcServer 类,因为它们几乎可以完成您需要的所有工作。

回答by dalelane

thanks to Arachnid for the answer - it worked as suggested

感谢 Arachnid 的回答 - 它按建议工作

here is a simplified copy of the code, in case it is helpful to the next person to try!

这里是代码的简化副本,以防对下一个人尝试有帮助!

import os
import urllib
import urllib2
import cookielib

users_email_address = "[email protected]"
users_password      = "billybobspassword"

target_authenticated_google_app_engine_uri = 'http://mylovelyapp.appspot.com/mylovelypage'
my_app_name = "yay-1.0"



# we use a cookie to authenticate with Google App Engine
#  by registering a cookie handler here, this will automatically store the 
#  cookie returned when we use urllib2 to open http://currentcost.appspot.com/_ah/login
cookiejar = cookielib.LWPCookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar))
urllib2.install_opener(opener)

#
# get an AuthToken from Google accounts
#
auth_uri = 'https://www.google.com/accounts/ClientLogin'
authreq_data = urllib.urlencode({ "Email":   users_email_address,
                                  "Passwd":  users_password,
                                  "service": "ah",
                                  "source":  my_app_name,
                                  "accountType": "HOSTED_OR_GOOGLE" })
auth_req = urllib2.Request(auth_uri, data=authreq_data)
auth_resp = urllib2.urlopen(auth_req)
auth_resp_body = auth_resp.read()
# auth response includes several fields - we're interested in 
#  the bit after Auth= 
auth_resp_dict = dict(x.split("=")
                      for x in auth_resp_body.split("\n") if x)
authtoken = auth_resp_dict["Auth"]

#
# get a cookie
# 
#  the call to request a cookie will also automatically redirect us to the page
#   that we want to go to
#  the cookie jar will automatically provide the cookie when we reach the 
#   redirected location

# this is where I actually want to go to
serv_uri = target_authenticated_google_app_engine_uri

serv_args = {}
serv_args['continue'] = serv_uri
serv_args['auth']     = authtoken

full_serv_uri = "http://mylovelyapp.appspot.com/_ah/login?%s" % (urllib.urlencode(serv_args))

serv_req = urllib2.Request(full_serv_uri)
serv_resp = urllib2.urlopen(serv_req)
serv_resp_body = serv_resp.read()

# serv_resp_body should contain the contents of the 
#  target_authenticated_google_app_engine_uri page - as we will have been 
#  redirected to that page automatically 
#
# to prove this, I'm just gonna print it out
print serv_resp_body

回答by ryan

for those who can't get ClientLogin to work, try app engine's OAuth support.

对于那些无法让 ClientLogin 工作的人,请尝试应用引擎的OAuth 支持

回答by Sean O Donnell

Im not too familiar with AppEngine, or Googles web apis, but for a brute force approach you could write a script with something like mechanize (http://wwwsearch.sourceforge.net/mechanize/) to simply walk through the login process before you begin doing the real work of the client.

我对 AppEngine 或 Google 的 web apis 不太熟悉,但是对于蛮力方法,您可以编写一个类似 mechanize ( http://wwwsearch.sourceforge.net/mechanize/)的脚本来简单地在您之前完成登录过程开始做客户的实际工作。

回答by Sean O Donnell

I'm not a python expert or a app engine expert. But did you try following the sample appl at http://code.google.com/appengine/docs/gettingstarted/usingusers.html. I created one at http://quizengine.appspot.com, it seemed to work fine with Google authentication and everything. Just a suggestion, but look in to the getting started guide. Take it easy if the suggestion sounds naive. :) Thanks.

我不是 Python 专家或应用引擎专家。但是您是否尝试遵循http://code.google.com/appengine/docs/gettingstarted/usingusers.html 上的示例应用程序。我在http://quizengine.appspot.com 上创建了一个,它似乎与 Google 身份验证和一切配合良好。只是一个建议,但请查看入门指南。如果这个建议听起来很幼稚,请放轻松。:) 谢谢。