gpt4 book ai didi

google-app-engine - Google Endpoints API + Chrome 扩展为 endpoints.get_current_user().user_id() 返回 None

转载 作者:太空宇宙 更新时间:2023-11-03 15:18:42 36 4
gpt4 key购买 nike

我正在开发用 Python 编写并使用 Endpoints API 的 Google App Engine 应用程序。同时,我正在编写一个 Chrome 扩展来与 Endpoints API 交互。我在 Endpoints API 和授权方面遇到了很多问题。目前,这是我的设置:

端点 API (Python)

from google.appengine.ext import endpoints
from protorpc import message_types
from protorpc import remote

ALLOWED_CLIENT_IDS = ['client_id_from_google_api_console',
endpoints.API_EXPLORER_CLIENT_ID]

@endpoints.api(name='my_api',version='v1', description='My API',
allowed_client_ids=ALLOWED_CLIENT_IDS)
class MyApi(remote.Service):

@endpoints.method(message_types.VoidMessage, DeviceListResponse,
name='user.device.list', path='user/device/list',
http_method='GET')
def user_device_list(self, request):
current_user = endpoints.get_current_user()
if current_user is None:
raise endpoints.UnauthorizedException('You must authenticate first.')
if current_user.user_id() is None:
raise endpoints.NotFoundException("Your user id was not found.")

return DeviceListResponse(devices=[]) #Hypothetically return devices

api_service = endpoints.api_server([MyApi], restricted=False)

谷歌 API 控制台

JS起源包括:
chrome-extensions://chrome_app_id

Chrome 扩展 (JS)
var apiRoot = "https://my_app_id.appspot.com/_ah/api";
var clientID = "client_id_from_google_api_console";
var oauthScopes = ["https://www.googleapis.com/auth/userinfo.email"];
var responseType = "token id_token";

//Helper method to log to the console
function l(o){console.log(o);}

function oauthSignin(mode) {
gapi.auth.authorize({client_id: clientID, scope: oauthScopes,
immediate: mode, response_type: responseType}, function() {
var request = gapi.client.oauth2.userinfo.get();
request.execute(function(resp) {
authenticated = !resp.code;
if(authenticated) {
var token = gapi.auth.getToken();
token.access_token = token.id_token;
gapi.auth.setToken(token);
l("Successfully authenticated. Loading device list");
gapi.client.my_api.user.device.list({}).execute(function(resp) {
if(resp.code) {
l("Response from device list: " + resp.message);
}
l(resp);
});
}
});
});
}


//This get's called when the page and js library has loaded.
function jsClientLoad() {
l("JS Client Libary loaded. Now loading my_api and oauth2 APIs.");
var apisToLoad;
var callback = function() {
if (--apisToLoad == 0) {
l("APIs have loaded.")
oauthSignin(true);
} else {
l("Waiting for " + apisToLoad + " API" + (apisToLoad>1?"s":"") + " to load.");
}
}

apisToLoad = 2; // must match number of calls to gapi.client.load()
gapi.client.load('my_api', 'v1', callback, apiRoot);
gapi.client.load('oauth2', 'v2', callback);
}

结果

现在我已经展示了我的代码的主要部分(注意,我必须在不上传整个代码的情况下对其进行一些更改才能使其有意义),如果我转到 Google API Explorer 并运行该方法,我会得到 200 响应。如果我在 Chrome 扩展程序中运行它,我会收到一个 404 代码,并显示消息“找不到您的用户 ID。”。

最佳答案

目前尚不清楚为什么/何时会导致 200 ;不应该。如 Function User.getUserId() in Cloud endpoint api returns null for a user object that is not null 中所述,这是一个 known issue .

TLDR;
user_id从不 填充在从 endpoints.get_current_user() 返回的结果中.存在一种解决方法:通过将用户对象存储在数据存储区中,然后检索它(使用新的 get,如果您使用的是 ndb),则 user_id()值将被填充。

您应该强烈考虑使用与帐户关联的 Google 个人资料 ID,而不是 App Engine 用户 ID。

历史/解释:
endpoints旨在与不记名 token 和 ID token (适用于 Android)一起使用。 ID token 是一种特殊类型的 JWT(JSON Web token ),与设备加密一起签名。因此,从这些 token 中解析用户只能确定该 token 中编码的信息(有关更多信息,请参阅 Cloud endpoints oauth2 error)。

由于这些 token 是由 App Engine 之外的通用 Google 身份验证提供程序 (OAuth 2.0) 生成的,因此该服务不知道/不共享 App Engine 用户 ID。结果是从不 可以填充 user_id()当 ID token 用于签署请求时。

当使用标准的不记名 token (这对您的 Chrome 应用程序很好)时,App Engine OAuth API用来。当 OAuth API 调用时

oauth.get_current_user(some_scope)

(其中 oauthgoogle.appengine.api.oauth ),
oauth.oauth_api._maybe_call_get_oauth_user(_scope=None)

method叫做。这使得 RPC到共享 App Engine 层,该层提供能够从 token 获取当前用户的服务。在 本案 , user_id()返回用户的 威尔设置,但是,用户值不会保留在 endpoints.get_current_user 周围。 ,只有电子邮件和身份验证域。

另一种解决方法:
oauth.get_current_user()通话才贵 如果 它使RPC。 _maybe_call_get_oauth_user方法存储上次调用的值,因此调用 oauth.get_current_user()除了从 Python 中查找值的几纳秒之外,第二次不会产生网络/速度开销 dict .

这很重要,因为 endpoints.get_current_user()使用调用 oauth.get_current_user()来确定 Bearer token 用户,因此如果您想再次调用它,您会担心该性能。

如果您知道自己永远不会使用 ID token ,或者可以轻松确定这些情况,则可以将代码更改为仅调用两者:
endpoints_user = endpoints.get_current_user()
if endpoints_user is None:
raise endpoints.UnauthorizedException(...)

oauth_user = oauth.get_current_user(known_scope)
if oauth_user is None or oauth_user.user_id() is None:
# This should never happen
raise endpoints.NotFoundException(...)

注意 : 我们还是要打电话 endpoints.get_current_user()因为它始终确保我们的 token 仅针对我们允许的特定范围之一以及我们已列入白名单以与我们的应用程序对话的特定客户端 ID 之一类型转换。

注意 : 值 known_scope将根据您的哪个可能的范围与 token 匹配而有所不同。您的范围列表将在 endpoints.get_current_user() 之一中循环。 helper methods ,如果成功,最终匹配范围将存储为 os.getenv('OAUTH_LAST_SCOPE') .我强烈建议将此值用于 known_scope .

更好的选择:

如前所述,App Engine 用户 ID 根本无法从 ID token (目前)中隐含,但是, Google Profile ID可以用来代替 App Engine 用户 ID。 (此 ID 通常被视为 Google+ ID,尽管这在许多服务中都是一致的。)

确保此值与您的承载者相关联 ID token ,请确保您还请求非 userinfo.email 之一与 userinfo API 关联的范围:
  • https://www.googleapis.com/auth/plus.login
  • https://www.googleapis.com/auth/plus.me
  • https://www.googleapis.com/auth/userinfo.email
  • https://www.googleapis.com/auth/userinfo.profile

  • (此范围列表截至撰写本文时为 2013 年 5 月 20 日。)

    与不记名 token 案例中的 App Engine 用户 ID 类似,此 Google 个人资料 ID 被 endpoints.get_current_user() 丢弃。 , 但是 它适用于两种 token 。
    get_google_plus_user_id() method这是 appengine-picturesque-python 的一部分示例补丁之一 endpoints.get_current_user() helper 方法来保留此数据并允许您使用此值,而无需重复用于验证请求中的 Bearer 或 ID token 的昂贵网络调用。

    关于google-app-engine - Google Endpoints API + Chrome 扩展为 endpoints.get_current_user().user_id() 返回 None,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16661109/

    36 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com