如何通过(非网页)Python客户端访问经过身份验证的Google App Engine服务?
我有一个Google App Engine的应用 - http://mylovelyapp.appspot.com/,里面有一个页面 - mylovelypage。
目前,这个页面只做了一件事,就是 self.response.out.write('OK')
。
如果我在我的电脑上运行以下Python代码:
import urllib2
f = urllib2.urlopen("http://mylovelyapp.appspot.com/mylovelypage")
s = f.read()
print s
f.close()
它会打印出“OK”。
问题是,如果我在应用的yaml文件中给这个页面加上 login:required
,
那么它就会显示出Google账户登录页面的HTML代码。
我尝试了一些“正常”的认证方法,比如:
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(None,
uri='http://mylovelyapp.appspot.com/mylovelypage',
user='billy.bob@gmail.com',
passwd='billybobspasswd')
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
但是没有任何效果 - 我还是得到了登录页面的HTML。
我还试过Google的ClientLogin认证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" % ("billy.bob@gmail.com", "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
我似乎能正确获取到一些令牌,但当我在请求'mylovelypage'时,把它放到请求头里,结果还是只返回登录页面的HTML。:-(
有没有人能帮帮我?
我可以使用GData客户端库来做这种事情吗?根据我所读到的,我觉得它应该能访问App Engine的应用,
但我在让App Engine的认证正常工作方面也没有成功。
如果有人能给我一些示例、文章,或者一些我应该搜索的关键词,我会非常感激。
谢谢!
5 个回答
如果你发现ClientLogin无法正常使用,可以试试应用引擎的OAuth支持。
感谢Arachnid的回答 - 按照建议的方法确实有效
这里有一份简化版的代码,可能对下一个尝试的人有帮助!
import os
import urllib
import urllib2
import cookielib
users_email_address = "billy.bob@gmail.com"
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
appcfg.py是一个工具,用来把数据上传到App Engine,它需要通过特定的方式来验证自己和App Engine服务器的身份。相关的功能被封装在appengine_rpc.py里。简单来说,解决方案是这样的:
- 使用Google ClientLogin API来获取一个认证令牌。appengine_rpc.py在_GetAuthToken这个地方完成这个步骤。
- 把这个认证令牌发送到你App Engine应用的一个特殊网址。这个页面会返回一个cookie和一个302重定向。你可以忽略这个重定向,只需保存这个cookie。appcfg.py在_GetAuthCookie里处理这个过程。
- 在以后的所有请求中都使用这个返回的cookie。
你可能还想看看_Authenticate,了解appcfg是如何处理ClientLogin返回的各种状态码的,以及_GetOpener,看看appcfg是如何创建一个不跟随HTTP重定向的urllib2 OpenerDirector的。其实,你也可以直接使用AbstractRpcServer和HttpRpcServer这两个类,因为它们几乎可以满足你所有的需求。