Google+ API错误 - 凭据无效

时间:2013-09-11 13:26:17

标签: coldfusion google-plus

我正在使用Google+帐户与用户签名。我签了他们并获取基本信息并将其存储在数据库中。在此过程中,我将access_token存储在会话中并继续。

但是,今天我正在尝试编写一个脚本,允许我使用他们的会话access_token在Google+上发布他们的“片刻”。

我收到错误,响应如下:

{ "error": { "errors": [ { "domain": "global", "reason": "authError", "message": "Invalid Credentials", "locationType": "header", "location": "Authorization" } ], "code": 401, "message": "Invalid Credentials" } } 

我不确定为什么会发生这种情况,下面是我用来发出请求的代码(它在ColdFusion脚本中,但即使你不知道这种语法,你也应该能够看到它背后的原理)

local.http = new http();
local.http.setMethod("post"); 
local.http.setCharset("utf-8"); 
local.http.setUseragent(cgi.http_user_agent);
local.http.setResolveurl(true);
local.http.setTimeout(20);
local.http.setUrl("https://www.googleapis.com/plus/v1/people/" & session.user.sourceid & "/moments/vault");

local.target = {};
local.target["kind"]        = "plus##moment";
local.target["type"]        = "http://schemas.google.com/AddActivity";
local.target["description"] = params.pin["description"];
local.target["image"]       = session.user.image;
local.target["name"]        = params.pin["title"];
local.target["url"]         = URLfor(route="pinShow", key=obfuscateParam(pin.id), onlyPath=false);
local.target["latitude"]    = session.user.latitude;
local.target["longitude"]   = session.user.longitude;

local.http.addParam(type="formField", name="target", value=serialize(local.target));
local.http.addParam(type="formField", name="kind", value="plus##moment");
local.http.addParam(type="formField", name="type", value="http://schemas.google.com/AddActivity");
local.http.addParam(type="formField", name="access_token", value=session.access_token);
local.result = local.http.send().getPrefix();

正如你所看到的,这一切似乎都是直截了当的。

我在登录后直接测试了这一点,尽管如此,它表示令牌在标题响应中无效:

HTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="https://www.google.com/accounts/AuthSubRequest", error=invalid_token Content-Type: application/json; charset=UTF-8 Content-Encoding: gzip Date: Wed, 11 Sep 2013 13:12:28 GMT Expires: Wed, 11 Sep 2013 13:12:28 GMT Cache-Control: private, max-age=0 X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block Content-Length: 162 Server: GSE Alternate-Protocol: 443:quic 

有谁知道为什么会这样,以及如何解决它?

我没有使用任何类型的库,因为没有ColdFusion的库。此外,我不想,因为我的需求只是非常基本,我想看看它是如何工作的。

我错过了一些明显的东西吗?

任何帮助都会非常感激,因为它让我疯了!

谢谢, MIKEY。

PS - 我已经从我的帐户中删除了该应用,清除了所有Cookie和会话,然后再次登录授予所有权限,因此它似乎已被淘汰。

更新1:

在这里发现其他用户的一些亮光后,我发现我应该在HTTP正文中发布一个JSON响应来发出请求。所以我把我的代码更改为:

local.request = {}
local.request["kind"]       = "plus##moment";
local.request["type"]       = "http://schemas.google.com/AddActivity";
local.request["target"]     = {};
local.request.target["kind"]        = "plus##itemScope";
local.request.target["type"]        = "http://schemas.google.com/AddActivity";
local.request.target["description"] = params.pin["description"];
local.request.target["image"]       = session.user.image;
local.request.target["name"]        = params.pin["title"];
local.request.target["url"]         = URLfor(route="pinShow", key=obfuscateParam(pin.id), onlyPath=false);
local.request.target["latitude"]    = session.user.latitude;
local.request.target["longitude"]   = session.user.longitude;

local.http = new http();
local.http.setMethod("post"); 
local.http.setCharset("utf-8"); 
local.http.setUseragent(cgi.http_user_agent);
local.http.setResolveurl(true);
local.http.setTimeout(20);
local.http.setUrl("https://www.googleapis.com/plus/v1/people/" & session.user.sourceid & "/moments/vault?debug=true&fields=kind%2Ctype%2Cdescription%2Cimage%2Curl&key={GOOLE_API_KEY}" );
local.http.addParam(type="header", name="Content-Type", value="application/json");
local.http.addParam(type="header", name="Authorization", value="Authorization: Bearer " & session.access_token);
local.http.addParam(type="body", value=serializeJSON(local.request));

local.result = local.http.send().getPrefix();

但是,现在我收到另一个错误(401未经授权):

{ "error": { "errors": [ { "domain": "global", "reason": "required", "message": "Login Required", "locationType": "header", "location": "Authorization" } ], "code": 401, "message": "Login Required" } } 

有人知道如何使用上面的新方法传递access_token吗?

更新2

我一直强调,这可能源于我最初的OAuth 2流程。我已从Google+帐户中删除该应用,并再次启动确认/登录过程。这是生成的URL:

  

https://accounts.google.com/ServiceLogin?service=lso&passive=1209600&continue=https://accounts.google.com/o/oauth2/auth?response_type%3Dcode%26scope%3Dhttps://www.googleapis.com/auth/userinfo.email%2Bhttps://www.googleapis.com/auth/userinfo.profile%2Bhttps://www.googleapis.com/auth/plus.login%26redirect_uri%3Dhttp:// {MY_DOMAIN}的.com / OAuth的/谷歌/?做%253Dredirect%26state%3D2BFFBC14-29F9-4488-ABBF661C0E9E53DB%26client_id%3D {MY_CLIENT_ID}%26hl%3Den-GB%26from_login%3D1% 26AS%3D-593afcc82466f5f&安培; ltmpl =弹出&安培; SHDF = CnALEhF0aGlyZFBhcnR5TG9nb1VybBoADAsSFXRoaXJkUGFydHlEaXNwbGF5TmFtZRoIVW5pYmFuZHMMCxIGZG9tYWluGghVbmliYW5kcwwLEhV0aGlyZFBhcnR5RGlzcGxheVR5cGUaB0RFRkFVTFQMEgNsc28iFOyetn24YRlbdWKLAKGXFCH5C1p9KAEyFPquOHBH18K6iV1GTAg_P9zB2x60&安培; SARP = 1&安培; SCC = 1

我在这里遗漏了什么吗?它是一个缺少的范围,应该允许我发布到他们的AddActivity流吗?

更新3

我的OAuth登录网址(我尝试拆分新行以提高可读性):

  

https://accounts.google.com/o/oauth2/auth?范围=   HTTPS%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile +   HTTPS%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email +   HTTPS%3A%2F%2Fwww.googleapis.com%2Fauth%2Fplus.login&安培;   request_visible_actions =   HTTPS%3A%2F%2Fschemas.google.com%2FAddActivity&安培;状态=   65B4A4D1-0C49-4C65-9B46163E67D88EAD&安培; REDIRECT_URI =   HTTP%3A%2F%2FXXXXXXX.com%2Foauth%2Fgoogle%2F%3Fdo%3Dredirect&安培;   response_type = code& client_id = XXXXXXXX.apps.googleusercontent.com

在Google+上的权限屏幕上,这就是我看到的内容:

enter image description here

当我尝试发布addActivity时,我得到了一个错误的请求错误。

JSON返回错误:

{ "error": { "errors": [ { "domain": "global", "reason": "invalid", "message": "Invalid Value" } ], "code": 400, "message": "Invalid Value" } }

标题返回:

HTTP/1.1 400 Bad Request Content-Type: application/json; charset=UTF-8 Content-Encoding: gzip Date: Fri, 13 Sep 2013 11:38:20 GMT Expires: Fri, 13 Sep 2013 11:38:20 GMT Cache-Control: private, max-age=0 X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block Content-Length: 123 Server: GSE Alternate-Protocol: 443:quic 

4 个答案:

答案 0 :(得分:2)

至少有一个标题存在明确问题:

local.http.addParam(type="header", name="Authorization", value="Authorization: Bearer " & session.access_token);

你有两次授权,应该是。

local.http.addParam(type="header", name="Authorization", value="Bearer " & session.access_token);

人们可能会发生什么事情。电话是它正在拿起API密钥并公开返回而不是签名用户。

正如Brett所说,要编写应用活动,您需要将& request_visible_actions = http://schemas.google.com/AddActivity添加到您首先向用户发送的auth URL(如果不使用JS登录按钮),为了让用户批准你写这种动作(就像另一种类型的范围)。

答案 1 :(得分:1)

你究竟是如何获得访问令牌的?你在使用OAuth吗?

您每次使用新的访问令牌吗?不是在DB中存储一次的那个?您需要记住,令牌可以很快到期。

这一位: “reason”:“authError”,“message”:“Invalid Credentials”,“locationType”:“header”,“location”:“Authorization”

可能意味着您的Authorization标头不正确 - 我怀疑不存在,因为我看不到您提供的代码中发送任何签名。

我没有使用过G + API,但您似乎需要使用正确的OAuth 2.0来获取任何数据: https://developers.google.com/+/api/latest/people/get#examples

这里有一个OA库的CF库http://oauth.riaforge.org/

更新:

如果您到这里:https://developers.google.com/+/api/latest/moments/insert#try-it并尝试运行示例(使用“我”)作为用户ID,您将看到请求如下所示:

POST https://www.googleapis.com/plus/v1/people/me/moments/vault?debug=true&key={YOUR_API_KEY}

Content-Type:  application/json
Authorization:  Bearer ya29.XXXXXXXXXXXXXXXXXXXXXXXXXXXX

您需要提供“授权”标头。

答案 2 :(得分:1)

虽然我对ColdFusion并不完全熟悉,但看起来你可能在这里混合了两个不能混合的概念。 access_token通常在HTTP标头中指定,或者作为URL查询参数指定。它通常不设置为POST参数,这可能是问题的一部分。

如果在标头中完成,HTTP标头应为

Authorization: Bearer 1/fFBGRNJru1FQd44AzqT3Zg

如果使用URL查询参数,您的网址可能需要类似

https://www.googleapis.com/plus/v1/people/123456789012345/moments/vault?access_token=1/fFBGRNJru1FQd44AzqT3Zg

有关详细信息,请参阅https://developers.google.com/accounts/docs/OAuth2UserAgent#callinganapi

不确定这是否相关,虽然它可能是,但我不确定你的POST的正文是否正确。您没有为正文设置内容类型,我不知道CF是否会使用类似“application / www-form-url-encoded”或“multipart / form-data”的内容,这些都不是有效的。正文应该是“application / json”。

<强>更新

因此,考虑到您更改的代码,您可能希望setUrl行类似于

local.http.setUrl("https://www.googleapis.com/plus/v1/people/" & session.user.sourceid & "/moments/vault?access_token=" & session.access_token );

我在上面提供的网址为Google提供了OAuth2的权威文档。我不确定您尝试添加到URL的其他参数或原因,但如果它们必不可少,您可以通过这种方式在访问令牌之后添加它们。

答案 3 :(得分:1)

为响应更新2而修改

这听起来像是设置OAuth流程的问题。您似乎缺少基于您的OAuth生成的网址,您遗漏了request_visible_actions参数丢失或格式错误。

将以下查询参数添加到您的OAuth网址,这应该开始有效:

&request_visible_actions=http%3A%2F%2Fschemas.google.com%2FAddActivity

您的请求的另一个问题是您应该从请求中删除userinfo.profile范围。该范围不是必需的,因为您包含plus.login,可能会导致一些奇怪的问题。

最后,确保目标网址上的网页具有AddActivity moment type所需的最低级别schema.org元数据。这不是你现在的问题,但可能是你遇到的下一个问题。