Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 无法使用服务帐户授权连接到自己的GAE终结点API_Python_Google App Engine_Oauth 2.0_Service Accounts_Server To Server - Fatal编程技术网

Python 无法使用服务帐户授权连接到自己的GAE终结点API

Python 无法使用服务帐户授权连接到自己的GAE终结点API,python,google-app-engine,oauth-2.0,service-accounts,server-to-server,Python,Google App Engine,Oauth 2.0,Service Accounts,Server To Server,我一直在拼命尝试在Google App Engine(GAE)项目上成功地授权API,我正在使用OAuth2和服务帐户运行python脚本 我已经创建了服务帐户,将服务帐户id添加到api文件中允许的客户端id中,将私钥从.p12转换为.pem,并授权httplib2调用。我已尝试使用.authorize()方法传递凭据,并将凭据作为JSON加载,然后手动将access\u token参数添加到标头--{“Authorization”:“Bearer”+token\u string}。 API的

我一直在拼命尝试在Google App Engine(GAE)项目上成功地授权API,我正在使用OAuth2和服务帐户运行python脚本

我已经创建了服务帐户,将服务帐户id添加到api文件中允许的客户端id中,将私钥从.p12转换为.pem,并授权httplib2调用。我已尝试使用.authorize()方法传递凭据,并将凭据作为JSON加载,然后手动将access\u token参数添加到标头--
{“Authorization”:“Bearer”+token\u string}。

API的每次调用都会产生“无效令牌”

我注意到一件奇怪的事情,当我第一次调用SignedJwtAssertionCredentials时,凭证中没有访问令牌——“访问令牌”是None。但是,当我从存储器中的.dat文件检索凭据时,访问令牌确实会出现

以下是GAE endpoints_api.py文件、python_test.py文件和401响应

任何想法都将不胜感激

首先是应用程序引擎终结点服务器文件:

# endpoints_api.py running on GAE

import endpoints
import time
from protorpc import messages
from protorpc import message_types
from protorpc import remote

SERVICE_ACCOUNT_ID = 'random_account_id_string.apps.googleusercontent.com'
WEB_CLIENT_ID = 'random_web_client_id_string.apps.googleusercontent.com'
ANDROID_AUDIENCE = WEB_CLIENT_ID

package = "MyPackage"

class Status(messages.Message):
    message = messages.StringField(1)
    when = messages.IntegerField(2)

class StatusCollection(messages.Message):
    items = messages.MessageField(Status, 1, repeated=True)

STORED_STATUSES = StatusCollection(items=[
    Status(message='Go.', when=int(time.time())),
    Status(message='Balls.', when=int(time.time())),
    Status(message='Deep!', when=int(time.time())),
])

@endpoints.api(name='myserver', version='v1')
class MyServerApi(remote.Service):
    """MyServer API v1."""

    @endpoints.method(message_types.VoidMessage, StatusCollection,
                  allowed_client_ids=[SERVICE_ACCOUNT_ID,
                                      endpoints.API_EXPLORER_CLIENT_ID],
                  audiences=[ANDROID_AUDIENCE],
                  scopes=[endpoints.EMAIL_SCOPE],
                  path='status', http_method='GET',
                  name='statuses.listStatus')
    def statuses_list(self, unused_request):
        current_user = endpoints.get_current_user()
        if current_user is None:
            raise endpoints.UnauthorizedException('Invalid token.')
        else:
            return current_user.email(), STORED_STATUSES

APPLICATION = endpoints.api_server([MyServerApi])
接下来是本地python脚本:

# python_test.py file running from local server

from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import SignedJwtAssertionCredentials
import httplib2
import os.path
import json

SERVICE_ACCOUNT_EMAIL = "service_account_string@developer.gserviceaccount.com"
ENDPOINT_URL = "http://my-project.appspot.com/_ah/api/myserver/v1/status"
SCOPE = 'https://www.googleapis.com/auth/userinfo.email'
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))

f = file('%s/%s' % (SITE_ROOT, 'pk2.pem'), 'rb')
key = f.read()
f.close()

http = httplib2.Http()
storage = Storage('credentials.dat')
credentials = storage.get()

if credentials is None or credentials.invalid:
    credentials = SignedJwtAssertionCredentials(
        SERVICE_EMAIL, key, scope=SCOPE)
    storage.put(credentials)
else:
    credentials.refresh(http)

http = credentials.authorize(http)
headers = {'Content-Type': 'application/json'}

(resp, content) = http.request(ENDPOINT_URL,
                           "GET",
                           headers=headers)

print(resp)
print(content)
最后,控制台输出:

{'status':'401','alternative protocol':'443:quic,p=0.002','content length':'238','x-xss protection':'1;mode=block','x-content-type-options','nosniff','transfer-encoding','chunked','expires','Sun,2014年9月14日23:51:36 GMT','server','GSE','content-encoding','gzip','cache-control','private,max-age=0','date Sun,9月14日2014 23:51:36 GMT,“x-frame-options”:“SAMEORIGIN”,“内容类型”:“application/json;charset=UTF-8”,“www-authenticate”:“承载域=”https://accounts.google.com/AuthSubRequest“}


谢谢你的帮助。上面有几件事我做错了

首先,我需要在允许的id列表中引用appengine项目id

API_ID = 'project-id-number.apps.googleusercontent.com'

@endpoints.method(message_types.VoidMessage, StatusCollection,
              allowed_client_ids=[API_ID, SERVICE_ACCOUNT_ID,
                                  endpoints.API_EXPLORER_CLIENT_ID],
              audiences=[ANDROID_AUDIENCE],
              scopes=[endpoints.EMAIL_SCOPE],
              path='status', http_method='GET',
              name='statuses.listStatus')
我错误地认为build()方法只适用于官方的google API,但事实证明我引用的项目不正确。有了项目id,我可以使用build()而不是在服务器端文件中编写自己的httplib2调用(这不起作用)

删除“http=credentials.authorize(http)”下的代码时,我将其替换为以下内容:

myservice = build('my-service', 'v1', http=http, discoveryServiceUrl=discoveryServiceUrl)
data = myservice.my-path().endpoint-name()
results = data.execute()

这成功地授权了我的帐户并调用了endpoint.Woot!如果其他人对此有疑问,或者我的解决方案不清楚,请随时发表意见。这是一个痛苦的过程,我不希望对其他人有任何影响。

您必须使用上述方法吗?有一个OAuth装饰程序将为您处理所有的工作。它不会影响您非常需要重新编写代码。你给它你的OAtuh详细信息,它处理令牌和实际工作。我不知道我在说什么,但它看起来只在你在应用程序引擎环境中工作。如果你在外面,你需要提供私钥。我有一个解决方案,使用SignedJWTA做一些非常类似的事情sertionCredentials和build。我会将其作为答案发布。
myservice = build('my-service', 'v1', http=http, discoveryServiceUrl=discoveryServiceUrl)
data = myservice.my-path().endpoint-name()
results = data.execute()