如何在 Google App Engine 和本地开发服务器中使用带有私钥文件和模拟用户 (DWD) 的服务帐户?
How to use service account with private key file and impersonated user (DWD) in Google App Engine and local development server?
应用程序:Google App Engine Python 标准环境
目的:通过 google-api-python-client
访问 Google APIs(不是 Cloud APIs),例如Sheets API v4,通过使用 服务帐户并模拟用户 ,因为该应用程序应该代表该用户执行操作。 (双足认证,不会要求用户授予访问权限)
我在生产环境中设置了 运行,但它仅在本地开发服务器 (dev_appserver.py
) 上运行,用于测试是否会删除某个环境变量。我正在寻找一种无需 adding/removing 环境变量即可工作的解决方案。
为应用程序创建了服务帐户,并在管理控制台中配置了全域委派 DWD。工作表 API 已为此项目打开。
在许多可用的快速入门、示例和参考资料中,只有在阅读 Google Auth Library for Python documentation (google-auth
) 之后我才注意到缺少的部分(环境变量和SSL 库)并最终在生产环境中获得代码 运行。
应用代码将使用从 Cloud Console IAM 下载的私钥 JSON 文件。
requirements.txt
# as suggested by almost all docs, but this isn't everything we need:
google-api-python-client==1.6.5
google-auth==1.4.0
google-auth-httplib2==0.0.3
app.yaml
env_variables:
# enable socket support of paid app, needed for OAuth2 service-accounts
# see google-auth documentation, v1.4.1, chapter 1.2.4
GAE_USE_SOCKETS_HTTPLIB : true
# some other stuff
libraries:
# to make HTTPS calls to other services, needed for OAuth2 service-accounts
# see google-auth documentation, v1.4.1, chapter 1.2.4
- name: ssl
version: latest
appengine_config.py(表格 API v4 访问的部分示例)
from google.oauth2 import service_account
SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]
APP_ROOT_DIR = os.path.abspath(os.path.dirname(__file__))
SERVICE_ACCOUNT_FILE = "service-account-private-key.json"
import googleapiclient.discovery
credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
# impersonate as user@example.com (G Suite domain account)
credentials = credentials.with_subject('user@example.com')
service = googleapiclient.discovery.build('sheets', 'v4', credentials=credentials)
# until here, the code works in production and local dev server
result = service.spreadsheets().values().get(spreadsheetId="DOC-ID-HERE", range="A1:C5").execute()
# execute() will work only in production,
# on local dev, it will raise an ResponseNotReady exception
回溯
ERROR 2018-03-05 16:32:03,183 wsgi.py:263]
Traceback (most recent call last):
File "/Users/user/google-cloud-sdk/platform/google_appengine/google/appengine/runtime/wsgi.py", line 240, in Handle
handler = _config_handle.add_wsgi_middleware(self._LoadHandler())
File "/Users/user/google-cloud-sdk/platform/google_appengine/google/appengine/api/lib_config.py", line 351, in __getattr__
self._update_configs()
File "/Users/user/google-cloud-sdk/platform/google_appengine/google/appengine/api/lib_config.py", line 287, in _update_configs
self._registry.initialize()
File "/Users/user/google-cloud-sdk/platform/google_appengine/google/appengine/api/lib_config.py", line 160, in initialize
import_func(self._modname)
File "/Users/user/git/project/gae/appengine_config.py", line 143, in <module>
spreadsheetId=spreadsheetId, range=rangeName).execute()
File "/Users/user/git/project/gae/_lib/oauth2client/_helpers.py", line 133, in positional_wrapper
return wrapped(*args, **kwargs)
File "/Users/user/git/project/gae/_lib/googleapiclient/http.py", line 839, in execute
method=str(self.method), body=self.body, headers=self.headers)
File "/Users/user/git/project/gae/_lib/googleapiclient/http.py", line 166, in _retry_request
resp, content = http.request(uri, method, *args, **kwargs)
File "/Users/user/git/project/gae/_lib/google_auth_httplib2.py", line 187, in request
self._request, method, uri, request_headers)
File "/Users/user/git/project/gae/_lib/google/auth/credentials.py", line 121, in before_request
self.refresh(request)
File "/Users/user/git/project/gae/_lib/google/oauth2/service_account.py", line 322, in refresh
request, self._token_uri, assertion)
File "/Users/user/git/project/gae/_lib/google/oauth2/_client.py", line 145, in jwt_grant
response_data = _token_endpoint_request(request, token_uri, body)
File "/Users/user/git/project/gae/_lib/google/oauth2/_client.py", line 106, in _token_endpoint_request
method='POST', url=token_uri, headers=headers, body=body)
File "/Users/user/git/project/gae/_lib/google_auth_httplib2.py", line 116, in __call__
url, method=method, body=body, headers=headers, **kwargs)
File "/Users/user/git/project/gae/_lib/httplib2/__init__.py", line 1659, in request
(response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
File "/Users/user/git/project/gae/_lib/httplib2/__init__.py", line 1399, in _request
(response, content) = self._conn_request(conn, request_uri, method, body, headers)
File "/Users/user/git/project/gae/_lib/httplib2/__init__.py", line 1355, in _conn_request
response = conn.getresponse()
File "/Users/user/google-cloud-sdk/platform/google_appengine/google/appengine/dist27/python_std_lib/httplib.py", line 1121, in getresponse
raise ResponseNotReady()
我发现如果我从 app.yaml 的 env_variables
列表中删除 GAE_USE_SOCKETS_HTTPLIB
,该代码将在本地开发服务器上运行(但不再在生产环境中运行)。
我是不是做错了什么?我可以在两种环境中使用相同的代码(可能有一个小开关),而无需手动 adding/removing 来自 app.yaml 的变量吗?
- 目的:通过[=39=访问GoogleAPIs(不是云APIs) ],例如工作表 API v4, ....
Here 他们解释说:
Private, broadcast, multicast, and Google IP ranges (except those whitelisted below), are blocked:
- Google Public DNS: 8.8.8.8, 8.8.4.4, 2001:4860:4860::8888, 2001:4860:4860::8844 port 53
- Gmail SMTPS: smtp.gmail.com port 465 and 587
- Gmail POP3S: pop.gmail.com port 995
- Gmail IMAPS: imap.gmail.com port 993
- 我发现如果我从 app.yaml 的
env_variables
列表中删除 GAE_USE_SOCKETS_HTTPLIB
,该代码将在本地开发服务器上运行(但在生产了)。
这个解释here:
Using sockets with the development server
You can run and test code
using sockets on the development server, without using any special
command line parameters.
最后,这个 and the 描述了一个类似的场景。
希望这对你有帮助:-)
应用程序:Google App Engine Python 标准环境
目的:通过 google-api-python-client
访问 Google APIs(不是 Cloud APIs),例如Sheets API v4,通过使用 服务帐户并模拟用户 ,因为该应用程序应该代表该用户执行操作。 (双足认证,不会要求用户授予访问权限)
我在生产环境中设置了 运行,但它仅在本地开发服务器 (dev_appserver.py
) 上运行,用于测试是否会删除某个环境变量。我正在寻找一种无需 adding/removing 环境变量即可工作的解决方案。
为应用程序创建了服务帐户,并在管理控制台中配置了全域委派 DWD。工作表 API 已为此项目打开。
在许多可用的快速入门、示例和参考资料中,只有在阅读 Google Auth Library for Python documentation (google-auth
) 之后我才注意到缺少的部分(环境变量和SSL 库)并最终在生产环境中获得代码 运行。
应用代码将使用从 Cloud Console IAM 下载的私钥 JSON 文件。
requirements.txt
# as suggested by almost all docs, but this isn't everything we need:
google-api-python-client==1.6.5
google-auth==1.4.0
google-auth-httplib2==0.0.3
app.yaml
env_variables:
# enable socket support of paid app, needed for OAuth2 service-accounts
# see google-auth documentation, v1.4.1, chapter 1.2.4
GAE_USE_SOCKETS_HTTPLIB : true
# some other stuff
libraries:
# to make HTTPS calls to other services, needed for OAuth2 service-accounts
# see google-auth documentation, v1.4.1, chapter 1.2.4
- name: ssl
version: latest
appengine_config.py(表格 API v4 访问的部分示例)
from google.oauth2 import service_account
SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]
APP_ROOT_DIR = os.path.abspath(os.path.dirname(__file__))
SERVICE_ACCOUNT_FILE = "service-account-private-key.json"
import googleapiclient.discovery
credentials = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
# impersonate as user@example.com (G Suite domain account)
credentials = credentials.with_subject('user@example.com')
service = googleapiclient.discovery.build('sheets', 'v4', credentials=credentials)
# until here, the code works in production and local dev server
result = service.spreadsheets().values().get(spreadsheetId="DOC-ID-HERE", range="A1:C5").execute()
# execute() will work only in production,
# on local dev, it will raise an ResponseNotReady exception
回溯
ERROR 2018-03-05 16:32:03,183 wsgi.py:263]
Traceback (most recent call last):
File "/Users/user/google-cloud-sdk/platform/google_appengine/google/appengine/runtime/wsgi.py", line 240, in Handle
handler = _config_handle.add_wsgi_middleware(self._LoadHandler())
File "/Users/user/google-cloud-sdk/platform/google_appengine/google/appengine/api/lib_config.py", line 351, in __getattr__
self._update_configs()
File "/Users/user/google-cloud-sdk/platform/google_appengine/google/appengine/api/lib_config.py", line 287, in _update_configs
self._registry.initialize()
File "/Users/user/google-cloud-sdk/platform/google_appengine/google/appengine/api/lib_config.py", line 160, in initialize
import_func(self._modname)
File "/Users/user/git/project/gae/appengine_config.py", line 143, in <module>
spreadsheetId=spreadsheetId, range=rangeName).execute()
File "/Users/user/git/project/gae/_lib/oauth2client/_helpers.py", line 133, in positional_wrapper
return wrapped(*args, **kwargs)
File "/Users/user/git/project/gae/_lib/googleapiclient/http.py", line 839, in execute
method=str(self.method), body=self.body, headers=self.headers)
File "/Users/user/git/project/gae/_lib/googleapiclient/http.py", line 166, in _retry_request
resp, content = http.request(uri, method, *args, **kwargs)
File "/Users/user/git/project/gae/_lib/google_auth_httplib2.py", line 187, in request
self._request, method, uri, request_headers)
File "/Users/user/git/project/gae/_lib/google/auth/credentials.py", line 121, in before_request
self.refresh(request)
File "/Users/user/git/project/gae/_lib/google/oauth2/service_account.py", line 322, in refresh
request, self._token_uri, assertion)
File "/Users/user/git/project/gae/_lib/google/oauth2/_client.py", line 145, in jwt_grant
response_data = _token_endpoint_request(request, token_uri, body)
File "/Users/user/git/project/gae/_lib/google/oauth2/_client.py", line 106, in _token_endpoint_request
method='POST', url=token_uri, headers=headers, body=body)
File "/Users/user/git/project/gae/_lib/google_auth_httplib2.py", line 116, in __call__
url, method=method, body=body, headers=headers, **kwargs)
File "/Users/user/git/project/gae/_lib/httplib2/__init__.py", line 1659, in request
(response, content) = self._request(conn, authority, uri, request_uri, method, body, headers, redirections, cachekey)
File "/Users/user/git/project/gae/_lib/httplib2/__init__.py", line 1399, in _request
(response, content) = self._conn_request(conn, request_uri, method, body, headers)
File "/Users/user/git/project/gae/_lib/httplib2/__init__.py", line 1355, in _conn_request
response = conn.getresponse()
File "/Users/user/google-cloud-sdk/platform/google_appengine/google/appengine/dist27/python_std_lib/httplib.py", line 1121, in getresponse
raise ResponseNotReady()
我发现如果我从 app.yaml 的 env_variables
列表中删除 GAE_USE_SOCKETS_HTTPLIB
,该代码将在本地开发服务器上运行(但不再在生产环境中运行)。
我是不是做错了什么?我可以在两种环境中使用相同的代码(可能有一个小开关),而无需手动 adding/removing 来自 app.yaml 的变量吗?
- 目的:通过[=39=访问GoogleAPIs(不是云APIs) ],例如工作表 API v4, ....
Here 他们解释说:
Private, broadcast, multicast, and Google IP ranges (except those whitelisted below), are blocked:
- Google Public DNS: 8.8.8.8, 8.8.4.4, 2001:4860:4860::8888, 2001:4860:4860::8844 port 53
- Gmail SMTPS: smtp.gmail.com port 465 and 587
- Gmail POP3S: pop.gmail.com port 995
- Gmail IMAPS: imap.gmail.com port 993
- 我发现如果我从 app.yaml 的
env_variables
列表中删除GAE_USE_SOCKETS_HTTPLIB
,该代码将在本地开发服务器上运行(但在生产了)。
这个解释here:
Using sockets with the development server
You can run and test code using sockets on the development server, without using any special command line parameters.
最后,这个
希望这对你有帮助:-)