问题
I have successfully authorised my Google Apps Script app with the Xero API, and can get trial balances. However once I add a query string (?date=YYYY-mm-dd) to the request I get 401 - not authorised.
Adding the query string in the same way I've successfully used paging for getting payments and invoices.
Can anyone see the problem:
(The Gist)
function getTrialBalancesWithNoDate() {
// .
// .
// .
fetchPublicAppData('Reports/TrialBalance', '', '') // OK
// .
// .
// .
}
function getTrialBalancesWithDate() {
// .
// .
// .
fetchPublicAppData('Reports/TrialBalance', '2016-07-01', 'date') // Error - Not authorised
// .
// .
// .
}
function getInvoices() {
// .
// .
// .
fetchPublicAppData('Invoices', pageNumber, 'page') // OK
// .
// .
// .
}
function fetchPublicAppData(item, parameter, query) {
/* For PUBLIC APPLICATION TYPE */
if (typeof query !== 'undefined' && query !== '') {
query = query + '=' + parameter
} else {
query = ''
}
this.loadSettings(); // get latest settings
var requestURL = API_END_POINT + '/' + item ;
var oauth_signature_method = 'HMAC-SHA1';
var oauth_timestamp = (new Date().getTime()/1000).toFixed();
var oauth_nonce = Utils_.generateRandomString(Math.floor(Math.random() * 50));
var oauth_version = '1.0';
var signBase =
'GET' + '&' +
encodeURIComponent(requestURL) + '&' +
encodeURIComponent(
'oauth_consumer_key=' + this.consumerKey + '&' +
'oauth_nonce=' + oauth_nonce + '&' +
'oauth_signature_method=' + oauth_signature_method + '&' +
'oauth_timestamp=' + oauth_timestamp + '&' +
'oauth_token=' + this.accessToken + '&' +
'oauth_version=' + oauth_version + (query === '' ? '' : '&') +
query);
var sbSigned = Utilities
.computeHmacSignature(
Utilities.MacAlgorithm.HMAC_SHA_1,
signBase,
encodeURIComponent(this.consumerSecret) + '&' + encodeURIComponent(this.accessTokenSecret));
var oauth_signature = Utilities.base64Encode(sbSigned);
var authHeader =
"OAuth oauth_consumer_key=\"" + this.consumerKey +
"\",oauth_nonce=\"" + oauth_nonce +
"\",oauth_token=\"" + this.accessToken +
"\",oauth_signature_method=\"" + oauth_signature_method +
"\",oauth_timestamp=\"" + oauth_timestamp +
"\",oauth_version=\"1.0\",oauth_signature=\"" +
encodeURIComponent(oauth_signature) + "\"";
var headers = {"User-Agent": + this.userAgent, "Authorization": authHeader, "Accept": "application/json"};
var options = {"headers": headers, "muteHttpExceptions": false};
requestURL = requestURL + (query === '' ? '' : '?') + query
var response = UrlFetchApp.fetch(requestURL, options);
var responseCode = response.getResponseCode();
var responseText = response.getContentText();
if (responseCode === 200) {
return JSON.parse(responseText);
} else if (responseCode === 401) {
PropertiesService.getScriptProperties().setProperty('isConnected', 'false')
onOpen() // Reset menu
throw new Error('The Auth token has expired, run Xero > Settings (connect)');
} else {
throw new Error(responseText);
}
} // fetchPublicAppData()enter code here
回答1:
Your issue will be at this stage https://gist.github.com/andrewroberts/fed16cc1c7fed9c6d805ffd077efe8c7#file-trialbalance-gs-L58-L68.
When constructing your SignatgureBaseString for oauth 1.0a the order of the parameters matter. They must be ordered in lexicographical byte ordering.
A, B ... Y, Z, a, b ... y, z
In short that means params need to be ordered alphabetically, uppercase first and then lowercase.
In your example with query param
?date=YYYY-mm-dd
and how you are creating your signature base string, you will end up with your query param last, whereas it should be first.
date=... < oauth_consumer_key=...
The reason it was working correctly for your paging parameter is just that conveniently, 'page=...' would be the last parameter to be added after sorting them.
It's also worth noting that if your query param string was
?page=1&date=YYYY-mm-dd
you would need to split your query param string into its two params and sort/add them accoridingly
date=YYYY-mm-dd&oauth_consumer_key=blah&...&oauth_version=1.0&page=1
来源:https://stackoverflow.com/questions/38790332/xero-api-auth-fails-using-query-string-using-google-apps-script