Intuit API OAuth ApplicationAuthenticationFailed; код ошибки = 003200

Я использую эту библиотеку для OAuth v1.0 для подключения к QuickBooks Online API. Я успешно могу использовать трехстороннюю аутентификацию и возвращать токены доступа. Я также могу без проблем подключаться к большинству конечных точек. Однако у меня возникают проблемы с подключением к конечным точкам с параметрами URL.

Например, этот URL возвращается без проблем:

https://sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/customer/8

Однако этот URL-адрес возвращает SignatureBaseString: ошибка 401, неавторизованный.

//sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/query?query=select * from customer

Я что-то неправильно понимаю о том, как получить доступ к конечным точкам с параметрами URL в OAuth? Любая помощь или понимание будут оценены.

Рабочий код:

<cfset oAuthRequest = new com.brianflove.oauth.Request()>
<cfset oAuthConsumer = new com.brianflove.oauth.Consumer()>
<cfset oauthConsumer.setSecret(CONSUMER_SECRET)>
<cfset oauthConsumer.setKey(CONSUMER_KEY)>
<cfset oAuthRequest.setMethod("GET")>
<cfset oAuthRequest.setUrl("https://sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/customer/" & randrange(1,8))>
<cfset oAuthRequest.setConsumer(oAuthConsumer)>
<cfset oAuthRequest.setToken(session.token)>

<!---use HMAC-SHA1 signature method--->
<cfset signatureMethod = new com.brianflove.oauth.methods.HmacSha1SignatureMethod()>

<!---sign request--->
<cfset oAuthRequest.signWithSignatureMethod(signatureMethod=signatureMethod)>


<!---POST using request URL--->
<cfset httpRequest = new Http()>
<cfset httpRequest.setUrl(oAuthRequest.getUrl())>
<cfset httpRequest.setMethod(oAuthRequest.getMethod())>
<cfset httpRequest.addParam(type="header", name="Authorization", value=oAuthRequest.toHeader())>
<cfset httpRequest.addParam(type="header", name="Accept", value="application/json") />
<cfset httpRequest.setCharset("utf-8")>
<cfset httpResult = httpRequest.send().getPrefix()>

<cfdump var="#httpResult.filecontent#">

Нерабочий код:

<cfset oAuthRequest = new com.brianflove.oauth.Request()>
<cfset oAuthConsumer = new com.brianflove.oauth.Consumer()>
<cfset oauthConsumer.setSecret(CONSUMER_SECRET)>
<cfset oauthConsumer.setKey(CONSUMER_KEY)>
<cfset oAuthRequest.setMethod("GET")>
<cfset oAuthRequest.setUrl("https://sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/query?query=select * from customer") />
<cfset oAuthRequest.setConsumer(oAuthConsumer)>
<cfset oAuthRequest.setToken(session.token)>

<!---use HMAC-SHA1 signature method--->
<cfset signatureMethod = new com.brianflove.oauth.methods.HmacSha1SignatureMethod()>

<!---sign request--->
<cfset oAuthRequest.signWithSignatureMethod(signatureMethod=signatureMethod)>

<!---POST using request URL--->
<cfset httpRequest = new Http()>
<cfset httpRequest.setUrl(oAuthRequest.getUrl())>
<cfset httpRequest.setMethod(oAuthRequest.getMethod())>
<cfset httpRequest.addParam(type="header", name="Authorization", value=oAuthRequest.toHeader())>
<cfset httpRequest.addParam(type="header", name="Accept", value="application/json") />
<cfset httpRequest.setCharset("utf-8")>
<cfset httpResult = httpRequest.send().getPrefix()>

<cfdump var="#httpResult.filecontent#">

Ответ об ошибке:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<IntuitResponse time="2016-12-01T06:12:00.999-08:00" xmlns="http://schema.intuit.com/finance/v3">
    <Fault type="AUTHENTICATION">
        <Error code="3200">
            <Message>message=ApplicationAuthenticationFailed; errorCode=003200; statusCode=401</Message>
            <Detail>SignatureBaseString: GET&amp;https%3A%2F%2Fsandbox-quickbooks.api.intuit.com%2Fv3%2Fcompany%2F123145723805019%2Fquery&amp;oauth_consumer_key%3DqyprdTVZH2CtDAXewG1YQKQYzUssYH%26oauth_nonce%3D420ADB0BF9EF309B785C531EEE8A7AAF%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1480601520%26oauth_token%3Dqyprd5g2WEiaxaVyI3MqeXqRvxvi26cXuauyMtFQaMZHdjVT%26oauth_version%3D1.0%26query%3Dselect%2520%252A%2520from%2520customer</Detail>
        </Error>
    </Fault>
</IntuitResponse>

person Ryan Crutchfield    schedule 01.12.2016    source источник
comment
OAuth и ему подобные очень требовательны к подписям. Просто предположение, но я подозреваю, что подпись вычисляется неправильно, когда параметры строки запроса включаются непосредственно в URL-адрес. Вместо этого попробуйте добавить параметры к объекту oAuthRequest через addParameter().   -  person Leigh    schedule 01.12.2016
comment
@Leigh, спасибо - я думаю, что пробовал это раньше, но просто чтобы убедиться, что я попробовал это снова, используя ‹cfset oAuthRequest.setUrl(sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/) /› ‹cfset oAuthRequest.addParameter(key=query, value=select * from клиент) /› и получил такой же ответ   -  person Ryan Crutchfield    schedule 01.12.2016
comment
(Редактировать): Хорошо, на данный момент у меня нет идей, но я попробую позже, когда у меня будет шанс. А пока не могли бы вы опубликовать URL-адрес документов QB, показывающих пример клиента, который вы пытаетесь воспроизвести?   -  person Leigh    schedule 01.12.2016
comment
Я знаю, что это немного старомодно. Вы когда-нибудь догадывались об этом? Борьба с тем, что кажется одной и той же проблемой. (Хотя я работаю в Ruby.)   -  person jvillian    schedule 17.02.2017
comment
@Джвиллиан. жаль решение не найдено. удачи   -  person Ryan Crutchfield    schedule 01.03.2017
comment
Борьба с той же проблемой.   -  person user1124236    schedule 11.03.2017
comment
Я тоже, @user1124236...   -  person Cory Madden    schedule 21.07.2017


Ответы (1)


Закодируйте оператор запроса, прежде чем передавать его в URL-адрес.

Используйте приведенный ниже метод для выполнения кодирования:

<cffunction name="encodePercent" returntype="string" access="public"
            description="RFC 3986 encoding - keep [ALPHA, DIGIT, '-', '.', '_', '~'], %-encode the rest -> decoding '~', correctly encoding spaces('+') and '*'">
    <cfargument name="sValue"       required="true" type="string" hint="value to encode">
    <cfargument name="sEncoding"    required="false" type="string" default="UTF-8" hint="encoding">
    <cfset var sResult = "">
    <!--- using javacast to call the appropriate encode method --->
    <cfif Len(arguments.sValue)>
        <cfset sResult = CreateObject("java","java.net.URLEncoder").
                            encode(JavaCast("String",arguments.sValue), JavaCast("String",arguments.sEncoding))>
        <cfset sResult = Replace(sResult,"+","%20","all")>
        <cfset sResult = Replace(sResult,"*","%2A","all")>
        <cfset sResult = Replace(sResult,"%7E","~","all")>
    </cfif>

    <cfreturn sResult>
</cffunction>

Вы можете оставить значение аргумента «sEncoding» по умолчанию как есть.

person Tantely    schedule 02.12.2016
comment
спасибо но не работает. Я пробовал следующее: ‹cfset urlparam = encodePercent(select * from customer) /› ‹cfset oAuthRequest.setUrl(sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/ & urlparam & &minorversion=4) /› Он создает URL-адрес, который выглядит следующим образом: быстрые книги-песочницы. api.intuit.com/v3/company/123145723805019/ - person Ryan Crutchfield; 02.12.2016
comment
Если вы изучите остальную часть сгенерированного http-запроса, как он соотносится с их инструментом? Не обращая внимания на кодировку, казалось, что в нем есть правильные части, и заголовок Auth выглядел аналогично, хотя параметры oath_xxx, казалось, были в немного другом порядке (не уверен, что это имеет значение). - person Leigh; 02.12.2016
comment
@Leigh, если я использую их обозреватель API, он показывает следующий URI запроса: sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/ Заголовки запроса: Принять: application/json Авторизация: OAuth oauth_token=**** ********,oauth_nonce=77bb5009-69b1-4aad-ae3c-cb9dc66433d7,oauth_consumer_key=************,oauth_signature_method=HMAC-SHA1,oauth_timestamp=1480686014,oauth_version=1.0, oauth_signature=w1Z%2FHSG5ETeynZ4DN2RUr%2BTFOpQ%3D intuit_tid: idg-ajrnbybr1pfzjregh1gzsjo2-5535777 Агент пользователя: APIExplorer - person Ryan Crutchfield; 02.12.2016
comment
@Leigh Он также успешно работает с хром-приложением Postman. Я не уверен, имеет ли значение порядок переменных в авторизации. Я так не думаю. - person Ryan Crutchfield; 02.12.2016
comment
Вероятно, нет, но некоторые API придирчивы, поэтому стоит упомянуть. Попробуйте сравнить успешный запрос PostMan и заголовки http с теми, которые были сгенерированы CFC, чтобы увидеть, что выглядит иначе. Вы всегда можете изменить CFC, чтобы использовать одни и те же значения, если это необходимо (т. е. динамический материал, отметка времени, одноразовый номер и т. д.). - person Leigh; 02.12.2016
comment
Взял заголовки у почтальона (используя тот же токен) и скопировал их в заголовок авторизации в коде. Тот, у которого нет параметров URL, работал, поэтому заголовки должны быть правильными. Глядя на строку подписи больше или URL-адрес. - person Ryan Crutchfield; 02.12.2016
comment
С почтальоном вы можете увидеть необработанную строку (до подписания)? Сравнение этого с созданным в CF покажет вам, является ли проблема разницей в подписываемом значении или чем-то еще в процессе подписания. - person Leigh; 02.12.2016
comment
Я не вижу способа увидеть строку в Post Man или в проводнике API. - person Ryan Crutchfield; 03.12.2016