我正在尝试使用 Google 脚本创建一个附加组件以在 Google 电子表格中使用。
在附加组件中,我连接到需要我进行 OAuth 的第三方 API(此处为 Pocket API)。在使用 OAuth 时,我需要在调用 Pocket 的授权 API 时提供一个重定向 URI。
根据此链接上的信息: https://github.com/gsuitedevs/apps-script-oauth2,在这种情况下,重定向 URI 的格式为 https://script.google.com/macros/d/ {SCRIPT ID }/用户回调。我使用了这种格式,但出现“无法打开文件”的错误。我使用“OAuth2.getRedirectUri()”来获取重定向 URI。
澄清我得到的评论:我没有直接打开重定向 URI。我在对 Pocket API 的调用中指定了它。这是完整的代码:
/**
* @OnlyCurrentDoc Limits the script to only accessing the current spreadsheet.
*/
var API_KEY = '87572-369f6490c104433f539c40d6';
var FIRST_TOKEN = '';
/**
* Adds a custom menu with items to show the sidebar and dialog.
*
* @param {Object} e The event parameter for a simple onOpen trigger.
*/
function onOpen(e) {
SpreadsheetApp.getUi()
.createAddonMenu()
.addItem('Show articles', 'getPocketArticles')
.addToUi();
}
/**
* Runs when the add-on is installed; calls onOpen() to ensure menu creation and
* any other initializion work is done immediately.
*
* @param {Object} e The event parameter for a simple onInstall trigger.
*/
function onInstall(e) {
onOpen(e);
}
/*
*/
function getPocketArticles() {
// URL and params for the Pocket API
var root = 'https://getpocket.com/v3/';
var pocketService = getPocketService();
getPocketToken(root);
}
function getPocketToken(root) {
var url = root + 'oauth/request';
var payloadData = {
'consumer_key': API_KEY,
'redirect_uri': OAuth2.getRedirectUri(),
'state': ScriptApp.newStateToken()
.withMethod(usercallback)
.withTimeout(3600)
.createToken()
};
// parameters for url fetch
var params = {
'method': 'POST',
'contentType': 'application/json; charset=UTF8',
'headers': {
'X-Accept' : 'application/json'
},
'payload': JSON.stringify(payloadData)
};
Logger.log(params);
// call the Pocket API
var response = UrlFetchApp.fetch(url, params);
var data = response.getContentText();
var json = JSON.parse(data);
FIRST_TOKEN = json['code'];
Logger.log("First token: "+FIRST_TOKEN);
showSidebar(root);
}
/*
* Register the Pocket Service
*/
function getPocketService() {
// Create a new service with the given name. The name will be used when
// persisting the authorized token, so ensure it is unique within the
// scope of the property store.
return OAuth2.createService('pocket')
// Set the endpoint URLs.
//.setAuthorizationBaseUrl('https://getpocket.com/auth/authorize')
.setAuthorizationBaseUrl('https://getpocket.com/auth/authorize?request_token='+FIRST_TOKEN)
/*.setTokenUrl('')*/
// Set the client ID and secret, from the Google Developers Console.
.setClientId(API_KEY)
.setClientSecret(FIRST_TOKEN)
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('usercallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
// Set the scopes to request (space-separated for Google services).
/*.setScope('')*/
// Below are Google-specific OAuth2 parameters.
// Sets the login hint, which will prevent the account chooser screen
// from being shown to users logged in with multiple accounts.
//.setParam('login_hint', Session.getActiveUser().getEmail())
// Requests offline access.
//.setParam('access_type', 'offline')
// Forces the approval prompt every time. This is useful for testing,
// but not desirable in a production application.
//.setParam('approval_prompt', 'force');
.setTokenHeaders({
/*'Authorization': 'Basic ' +
Utilities.base64Encode(CLIENT_ID + ':' + CLIENT_SECRET),*/
'request_token': FIRST_TOKEN,
'X-Accept' : 'application/json'
})
/*
// Avoid "invalid_client error".
// This service does not support form field authentication.
.setTokenPayloadHandler(function(tokenPayload) {
delete tokenPayload.client_id;
return tokenPayload;
})*/
// Setting Payload
.setTokenPayloadHandler(function(tokenPayload) {
tokenPayload.state = ScriptApp.newStateToken()
.withMethod(usercallback)
.withTimeout(3600)
.createToken();
return tokenPayload;
})
;
}
/**
* Opens a sidebar. The sidebar structure is described in the Sidebar.html
* project file.
*/
function showSidebar(root) {
var pocketService = getPocketService();
var authorizationUrl = pocketService.getAuthorizationUrl();
Logger.log("Authorization URL: " + authorizationUrl);
if (!pocketService.hasAccess()) {
var template = HtmlService.createTemplate(
'<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. ' +
'Reopen the sidebar when the authorization is complete.');
template.authorizationUrl = authorizationUrl;
var page = template.evaluate();
SpreadsheetApp.getUi().showSidebar(page);
} else {
// ...
getPermanentToken(root);
}
}
/**
*
*/
function getPermanentToken(root) {
var url = root + 'oauth/authorize';
var payloadData = {
'consumer_key': API_KEY,
'code': FIRST_TOKEN
};
// parameters for url fetch
var params = {
'method': 'POST',
'muteHttpExceptions': false,
'contentType': 'application/json; charset=UTF8',
'headers': {
'X-Accept' : 'application/json'
},
'payload': JSON.stringify(payloadData)
};
/*'contentType': 'application/json',*/
// call the Pocket API
Logger.log("URL: "+url+"\nparams: "+JSON.stringify(params));
var response = UrlFetchApp.fetch(url, params);
Logger.log("Response: "+response.getAllHeaders());
}
/**
* Handle Callback
*
*/
function usercallback(request) {
var pocketService = getPocketService();
var isAuthorized = pocketService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
我是根据上面共享的 github 链接上给出的指南以及https://github.com/gsuitedevs/apps-script-oauth2/tree/master/samples上提到的示例完成此操作的。这些示例并不完全适用于我,因为 Pocket 的 API 的行为似乎有点不同(或者我理解)
我也为授权 URL 放置了记录器语句。它显示在我在下面共享的日志中。
执行记录日志:
[19-09-16 07:36:45:329 IST] Starting execution
[19-09-16 07:36:45:342 IST] PropertiesService.getUserProperties() [0 seconds]
[19-09-16 07:36:45:342 IST] ScriptApp.getScriptId() [0 seconds]
[19-09-16 07:36:45:344 IST] Logger.log([{headers={X-Accept=application/json}, method=POST, payload={"consumer_key":"87572-369f6490c104433f539c40d6","redirect_uri":"https://script.google.com/macros/d/1QWlUgkmucy_wXK3v1BUjbxh9Ei1bBan7AFL2Jce...) [0 seconds]
[19-09-16 07:36:45:513 IST] UrlFetchApp.fetch([https://getpocket.com/v3/oauth/request, {headers={X-Accept=application/json}, method=POST, payload={"consumer_key":"87572-369f6490c104433f539c40d6","redirect_uri":"https://script.google.com/macros/d/...) [0.168 seconds]
[19-09-16 07:36:45:513 IST] HTTPResponse.getContentText() [0 seconds]
[19-09-16 07:36:45:514 IST] Logger.log([First token: 5c9102f2-3feb-caa6-86f0-c4530e, []]) [0 seconds]
[19-09-16 07:36:45:515 IST] PropertiesService.getUserProperties() [0 seconds]
[19-09-16 07:36:45:516 IST] ScriptApp.newStateToken() [0 seconds]
[19-09-16 07:36:45:516 IST] StateTokenBuilder.withMethod([usercallback]) [0 seconds]
[19-09-16 07:36:45:517 IST] StateTokenBuilder.withArgument([serviceName, pocket]) [0 seconds]
[19-09-16 07:36:45:517 IST] StateTokenBuilder.withTimeout([3600]) [0 seconds]
[19-09-16 07:36:45:517 IST] ScriptApp.getScriptId() [0 seconds]
[19-09-16 07:36:45:517 IST] StateTokenBuilder.createToken() [0 seconds]
[19-09-16 07:36:45:518 IST] Logger.log([Authorization URL: https://getpocket.com/auth/authorize?request_token=5c9102f2-3feb-caa6-86f0-c4530e&client_id=87572-369f6490c104433f539c40d6&response_type=code&redirect_uri=https%3A%2F%2Fscript.goog...) [0 seconds]
[19-09-16 07:36:45:523 IST] Properties.getProperty([oauth2.pocket]) [0.005 seconds]
[19-09-16 07:36:45:525 IST] HtmlService.createTemplate([<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. Reopen the sidebar when the authorization is complete.]) [0.001 seconds]
[19-09-16 07:36:45:525 IST] Function.apply([[]]) [0 seconds]
[19-09-16 07:36:45:526 IST] HtmlService.createHtmlOutput() [0 seconds]
[19-09-16 07:36:45:527 IST] HtmlOutput.append([<a href="]) [0 seconds]
[19-09-16 07:36:45:528 IST] HtmlOutput.appendUntrusted([https://getpocket.com/auth/authorize?request_token=5c9102f2-3feb-caa6-86f0-c4530e&client_id=87572-369f6490c104433f539c40d6&response_type=code&redirect_uri=https%3A%2F%2Fscript.google.com%2Fmacros%2Fd...) [0 seconds]
[19-09-16 07:36:45:528 IST] HtmlOutput.append([" target="_blank">Authorize</a>. Reopen the sidebar when the authorization is complete.]) [0 seconds]
[19-09-16 07:36:45:529 IST] HtmlOutput.append([]) [0 seconds]
[19-09-16 07:36:45:530 IST] SpreadsheetApp.getUi() [0 seconds]
[19-09-16 07:36:45:595 IST] Ui.showSidebar([HtmlOutput]) [0.064 seconds]
[19-09-16 07:36:45:658 IST] Execution succeeded [0.255 seconds total runtime]
我在代码中的记录器语句的输出:
[19-09-16 07:36:45:343 IST] {headers={X-Accept=application/json}, method=POST, payload={"consumer_key":"87572-369f6490c104433f539c40d6","redirect_uri":"https://script.google.com/macros/d/1QWlUgkmucy_wXK3v1BUjbxh9Ei1bBan7AFL2JceT2401-ztkEtFk9-xb/usercallback"}, contentType=application/json; charset=UTF8}
[19-09-16 07:36:45:514 IST] First token: 5c9102f2-3feb-caa6-86f0-c4530e
[19-09-16 07:36:45:518 IST] Authorization URL: https://getpocket.com/auth/authorize?request_token=5c9102f2-3feb-caa6-86f0-c4530e&client_id=87572-369f6490c104433f539c40d6&response_type=code&redirect_uri=https%3A%2F%2Fscript.google.com%2Fmacros%2Fd%2F1QWlUgkmucy_wXK3v1BUjbxh9Ei1bBan7AFL2JceT2401-ztkEtFk9-xb%2Fusercallback&state=ADEpC8z2oP8q4juC4cgceCqVZw34DEX3KTdN9Cm5fPX-Nh7vzYIDdw50GIHNMfQ--Y92uqA_K8RUaAaHf7OU9O72RPOQ3ryYBVTrlQ-ZLZRQRgJ5Re68KOTud8ckAnonjG24a5-W2ti7g3o5rQebaDnhIlTLjY2MJWrP68pf70FSak6nhby7B_quV6PCmIjbCfS0R54D6oV3tTCwrL9JpO62zxmIHLkceD0O-cZc8SUrJK1yMDBcofuZCqGIxjlBOVpnCvugSnhCczp3qCaEA-3cLj3jwzXDX4XluqX7c-0hWsrkgHQNFxiB7qFo7pzhd8NlBcVj4t6yoQyTfquYN84C1wGKxcjtfg
发生的情况是,当我调用此 URL 时,我被重定向到 Pocket 授权页面,该页面要求我授权此加载项有权访问我的 Pocket 数据。这很好,但是当我点击授权时,我得到“无法打开文件”的错误。这是它的屏幕截图:https ://photos.app.goo.gl/VVCcEfh6NYTWK6MW9
我想知道我哪里出错了。有人可以指导我吗?
我是 Google Scripts 和 OAuth 的新手,所以如果这是一个愚蠢的问题,请原谅。