我正在创建一个OAuth身份验证流,这样我安装的应用程序的用户就可以访问他们的私人谷歌电子表格文档。我使用的是Adobe ExtendScript,所以我不能使用谷歌提供的Javascript客户端库。我已经多次阅读谷歌针对已安装应用程序的OAuth 2.0文档,但在OAuth流的某个方面需要帮助。我可以通过从安装的应用程序启动浏览器,让用户提交凭据,然后将授权码复制并粘贴回应用程序来获得授权码。然而,当我POST到端点以交换访问令牌的授权代码时,它不起作用。谷歌回复的正文显示:
Moved Temporarily
The document has moved <A HREF="https://accounts.google.com/o/oauth2/token">here</A>.
然而,我对href标记中的URL进行了POST调用。所以,我不知道为什么谷歌会告诉我,当我发布到同一个URL时,终点暂时移动了。这是我用来生成POST的代码。
function getAccessToken(authcode)
{
var http = require('http'),
OAuthAccessEndPoint = 'https://accounts.google.com/o/oauth2/token',
OAuthAccessParams = {};
OAuthAccessParams['code'] = authcode;
OAuthAccessParams['client_id'] = '{my_client_id}';
OAuthAccessParams['client_secret'] = '{my_client_secret}';
OAuthAccessParams['redirect_uri'] = 'urn:ietf:wg:oauth:2.0:oob';
OAuthAccessParams['grant_type'] = 'authorization_code';
var response = http.post(OAuthAccessEndPoint, OAuthAccessParams);
}
这篇帖子做得很好,但有人知道为什么谷歌会回应这个"暂时搬家"的通知吗?非常感谢您的任何建议!
编辑:只是澄清一下,这是我的剧本在原始版本中提出的请求:
POST /o/oauth2/token HTTP/1.1
User-Agent: Adobe ExtendScript
Accept: */*
Connection: close
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 226
code={authcode}&client_id={my_client_id}&client_secret={my_client_secret}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code&
如果我使用cURL中的授权代码以及其他参数,我确实会从谷歌的OAuth服务器得到成功的响应。所以,很明显,我的套接字与谷歌端点交互的方式出了问题,但我不确定是什么。是否可能有些组件需要进行URI编码,而其他组件则不需要?这是我正在使用的cURL:
#!/bin/bash
AUTHCODE="$1"
POSTCONTENT="code=$AUTHCODE&client_id={my_client_id}&client_secret={my_client_secret}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code&"
echo $POSTCONTENT
curl -v --data $POSTCONTENT https://accounts.google.com/o/oauth2/token
编辑2:因此,由于Sockets在Extendescript中不支持SSL,我编写了一个函数,使用操作系统级别的调用来调用请求。如果在OSX上,我们可以假设我们可以访问cURL,但在Windows上,我们必须编写一个VBScript,通过命令行中的cscript
主机执行。对于ExtendScript,以下是发出web请求的函数:
function webRequest(method, endpoint, query){
var response = null,
wincurl = WORKING_DIR.fsName + '\lib\curl.vbs',
curlCmd = '';
try {
if ( os() == "Win" ) {
curlCmd = 'cscript "' + wincurl + '" /Method:' + method + ' /URL:' + endpoint + ' /Query:' + query + ' //nologo';
} else {
if (method === "POST") {
curlCmd = 'curl -s -d "' + query + '" ' + endpoint;
} else if (method === "GET") {
curlCmd = 'curl -s -G -d "' + query + '" ' + endpoint;
}
}
response = system.callSystem(curlCmd);
} catch (err) {
alert("ErrornUnable to make a `"+ method +"` request to the network endpoint. Please try again.");
}
return response;
}
function os(){
var os = system.osName;
if (!os.length) { os = $.os; }
app_os = ( os.indexOf("Win") != -1 ) ? "Win" : "Mac";
return app_os;
}
这是从ExtendScript库调用的VBScript脚本。它需要三个参数,所有字符串:
set namedArgs = WScript.Arguments.Named
sMethod = namedArgs.Item("Method")
sUrl = namedArgs.Item("URL")
sRequest = namedArgs.Item("Query")
HTTPPost sMethod, sUrl, sRequest
Function HTTPPost(sMethod, sUrl, sRequest)
set oHTTP = CreateObject("Microsoft.XMLHTTP")
If sMethod = "POST" Then
oHTTP.open "POST", sUrl,false
ElseIf sMethod = "GET" Then
oHTTP.open "GET", sUrl,false
End If
oHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
oHTTP.setRequestHeader "Content-Length", Len(sRequest)
oHTTP.send sRequest
HTTPPost = oHTTP.responseText
WScript.Echo HTTPPost
End Function
您可以在任何API端点的ExtendScript中使用它,但响应将始终是字符串。因此,在Google的OAuth端点的情况下,您将得到一个看起来像JSON的字符串。所以,你必须用JSON.parse().
有关此问题的答案,请参阅上面的编辑。从本质上讲,它可以归结为ExtendScript中不支持SSL的Socket对象。上面的解决方案显示了一个变通方法,即在OSX上使用ExtendScript system.callSystem()方法获取cURL,在Windows上使用VBScript。