ben*_*dle 13 google-app-engine google-chrome-extension oauth-2.0 python-2.7 google-cloud-endpoints
我正在开发使用Python编写并使用Endpoints API的Google App Engine应用程序.与此同时,我正在编写Chrome扩展程序以与Endpoints API进行交互.我一直在使用Endpoints API和授权遇到很多问题.目前,这是我的设置:
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)
Run Code Online (Sandbox Code Playgroud)
JS的起源包括:chrome-extensions:// chrome_app_id
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);
}
Run Code Online (Sandbox Code Playgroud)
现在我已经展示了我的代码的主要部分(注意,我必须在不上传整个代码的情况下将其更改为有意义),如果我转到Google API Explorer并运行该方法,我会得到200响应.如果我在Chrome扩展程序中运行它,我会收到一条404代码,其中包含"找不到您的用户ID"的消息.
bos*_*ter 19
目前还不清楚为什么/何时会导致这种情况发生200; 它不应该.如云端点函数User.getUserId()中所述,api为非空的用户对象返回null,这是一个已知问题.
该user_id会永远从返回的结果来填充endpoints.get_current_user().存在一种解决方法:通过将用户对象存储在数据存储区中然后检索它(使用新的get,如果您正在使用ndb),user_id()将填充该值.
您应该强烈考虑使用与该帐户关联的Google个人资料ID,而不是App Engine用户ID.
endpoints用于承载令牌和ID令牌(适用于Android).ID令牌是与设备加密一起签名的特殊类型的JWT(JSON Web令牌).因此,从这些令牌中解析用户只能确定该令牌中编码的信息(有关详细信息,请参阅Cloud端点oauth2错误).
由于这些令牌由App Engine之外的通用Google Auth提供程序(OAuth 2.0)创建,因此该服务不知道/共享App Engine用户ID.因此,永远不可能填充user_id()ID令牌用于签署请求的时间.
使用标准的Bearer令牌(适用于您的Chrome应用程序)时,会使用App Engine OAuth API.OAuth API调用时
oauth.get_current_user(some_scope)
Run Code Online (Sandbox Code Playgroud)
(其中,oauth是google.appengine.api.oauth),则
oauth.oauth_api._maybe_call_get_oauth_user(_scope=None)
Run Code Online (Sandbox Code Playgroud)
方法被调用.这使得RPC成为共享App Engine层,该层提供能够从令牌获取当前用户的服务.在这种情况下,将设置user_id()返回用户的,但是,不保留用户值,仅保留电子邮件和auth域.endpoints.get_current_user
该oauth.get_current_user()电话只有昂贵的IF它使RPC.该_maybe_call_get_oauth_user方法存储来自最后一次调用的值,因此oauth.get_current_user()第二次调用将不会产生网络/速度开销,而不是几纳秒来从Python查找值dict.
这是至关重要的,因为endpoints.get_current_user()使用调用来oauth.get_current_user()确定承载令牌用户,所以如果你想再次调用它,你会担心这种性能.
如果您知道自己永远不会使用ID令牌或者可以轻松确定这些情况,那么您可以将代码更改为同时调用两者:
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(...)
Run Code Online (Sandbox Code Playgroud)
注意:我们仍然必须打电话,endpoints.get_current_user()因为它始终确保我们的令牌仅针对我们允许的特定范围之一以及我们已列入白名单与我们的应用程序通信的特定客户端ID之一.
注意:该值known_scope将根据您的可能范围与令牌匹配而有所不同.您的范围列表将在其中一个endpoints.get_current_user() 辅助方法中循环,如果成功,则最终匹配范围将存储为os.getenv('OAUTH_LAST_SCOPE').我强烈建议使用此值known_scope.
如上所述,App Engine用户ID根据ID令牌(当前)无法隐含,但是,可以使用Google Profile ID代替App Engine用户ID.(此ID通常被视为Google+ ID,但这在许多服务中都是一致的.)
要确保此值与您的Bearer OR ID令牌相关联,请确保您还请求userinfo.email与userinfoAPI关联的非范围之一:
https://www.googleapis.com/auth/plus.loginhttps://www.googleapis.com/auth/plus.mehttps://www.googleapis.com/auth/userinfo.emailhttps://www.googleapis.com/auth/userinfo.profile(截至2013年5月20日撰写的此范围列表.)
与承载令牌情况下的App Engine用户ID类似,此Google个人资料ID将被丢弃endpoints.get_current_user(),但它可用于两种令牌.
的get_google_plus_user_id() 方法,其是一部分appengine-picturesque-python样本碎片的一个endpoints.get_current_user()辅助的方法来围绕保持这个数据,并允许您使用此值,而无需重复用于从请求验证承载或ID令牌的昂贵的网络呼叫.
| 归档时间: |
|
| 查看次数: |
3089 次 |
| 最近记录: |