0

我正在尝试开发一个使用 Dropbox 的桌面应用程序。我正在使用 C++、libcurl(用于请求)liboauthcpp(用于身份验证)和 Rest API(来自 Dropbox)。

由于我已成功完成身份验证和一些其他操作(列出和下载文件),我无法上传文件。我收到以下错误:{"error": "Invalid signature."}

这是我的代码:

m_upload_url = "https://api-content.dropbox.com/1/files/sandbox/";

        OAuth::Consumer consumer(m_consumer_key, m_consumer_secret);
        OAuth::KeyValuePairs access_token_resp_data = OAuth::ParseKeyValuePairs(m_access_token_Response);
        OAuth::Token access_token = OAuth::Token::extract( access_token_resp_data );
        OAuth::Client  oauth = OAuth::Client(&consumer, &access_token);
        string oAuthQueryString = oauth.getURLQueryString( OAuth::Http::Post, m_upload_url);

        string upload_Request = (string(m_upload_url) + string("?") + oAuthQueryString);

       CURL *curl;
         CURLcode res;

         struct curl_httppost *formpost=NULL;
         struct curl_httppost *lastptr=NULL;
         struct curl_slist *headerlist=NULL;
         static const char buf[] = "Expect:";

         curl_global_init(CURL_GLOBAL_ALL);

         /* Fill in the file upload field */
         curl_formadd(&formpost,
                      &lastptr,
                      CURLFORM_COPYNAME, "file",
                      CURLFORM_FILE, "C:/Users/Desktop/textfile.txt",
                      CURLFORM_END);

         /* Fill in the filename field */
         curl_formadd(&formpost,
                      &lastptr,
                      CURLFORM_COPYNAME, "name",
                      CURLFORM_COPYCONTENTS, "textfile",
                      CURLFORM_END);


         /* Fill in the submit field too, even if this is rarely needed */
         curl_formadd(&formpost,
                      &lastptr,
                      CURLFORM_COPYNAME, "submit",
                      CURLFORM_COPYCONTENTS, "send",
                      CURLFORM_END);

         curl = curl_easy_init();
         /* initalize custom header list (stating that Expect: 100-continue is not
            wanted */
         headerlist = curl_slist_append(headerlist, buf);
         if(curl) {
           /* what URL that receives this POST */
           curl_easy_setopt(curl, CURLOPT_URL, upload_Request.c_str());
             /* only disable 100-continue header if explicitly requested */
           curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1L);
           curl_easy_setopt(curl, CURLOPT_POST, 1L);
           curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
           curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
           curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
           curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
           curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunction);
           curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

           /* Perform the request, res will get the return code */
           res = curl_easy_perform(curl);
           string response = string(gData);

           qDebug() << QString::fromStdString(response);

           /* Check for errors */
           if(res != CURLE_OK)
           qDebug() << "curl_easy_perform() failed: %s\n" << curl_easy_strerror(res);

           /* always cleanup */
           curl_easy_cleanup(curl);

           /* then cleanup the formpost chain */
           curl_formfree(formpost);
           /* free slist */
           curl_slist_free_all (headerlist);
         }

这是writeFunction:

char gData[1024*1024];
unsigned int gDataLen = 0;

size_t writeFunction( char *ptr, size_t size, size_t nmemb)
{
    memcpy( &( gData[gDataLen] ), ptr, (size * nmemb) );
    gDataLen += (size * nmemb);
    gData[ gDataLen ] = '\0';
    return (size * nmemb);
}

请问有什么想法吗?

编辑:

这是当前代码产生的请求: https://api-content.dropbox.com/1/files/sandbox/?oauth_consumer_key=xxxxxxxxxxxxxxx&oauth_nonce=13xxxxxx83cf&oauth_signature=xxxxxx%xxxxxxxxxxxxxxxxxx%xxxxx%xx&oauth_signature_method=HMAC-SHA1&oauth_timestamp=13711072xxxxxxxxxo&oauth_token= =1.0

以及我使用纯文本方法提出的请求: https ://api-content.dropbox.com/1/files/sandbox/?oauth_version=1.0&oauth_signature_method=PLAINTEXT&oauth_consumer_key=xxxxxxxxxxxxxxx&oauth_token=xxxxxxxxxxxxxxx&oauth_signature=xxxxxxxxxxxxxxx&xxxxxxxxxxxxxxx

O 在这两种情况下得到的响应:{"error": "Invalid signature."}

4

2 回答 2

1

您使用的是什么 OAuth 签名方法?如果它不是纯文本,那么我认为问题在于您没有将 HTTP 请求的正文传递给getURLQueryString. 正文需要是已签名字符串的一部分。这解释了为什么您能够进行一些GET操作。这些请求没有正文。

旁注:看起来您正在使用 POST 文件上传形式,正如文档所说,它比PUT复杂得多。我想如果你换了,你的生活会更好。:-) 例如,我认为submit您添加的字段可能会导致调用不起作用。

编辑:这是一个使用手动构建的明文签名的完整工作示例。填写应用程序密钥、应用程序密码、令牌和令牌密码,并确保有一个名为“hello.txt”的文件才能正常工作:

#include <stdio.h>
#include <curl/curl.h>
#include <iostream>
#include <fstream>

using namespace std;

size_t read_data(void *ptr, size_t size, size_t nmeb, void *stream)
{
    return fread(ptr,size,nmeb,(FILE*)stream);
}

int main(void)
{
  CURL *curl;
  CURLcode res;

  FILE * rfp = fopen("hello.txt", "r");

  string appkey = "<APP KEY>";
  string appsecret = "<APP SECRET>";
  string token = "<ACCESS TOKEN>";
  string token_secret = "<ACCESS TOKEN SECRET>";

  curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "https://api-content.dropbox.com/1/files_put/sandbox/hello.txt");

    struct curl_slist *headers = NULL;
    string header = "Authorization: OAuth oauth_version=\"1.0\", oauth_signature_method=\"PLAINTEXT\", oauth_consumer_key=\"" + appkey + "\", oauth_token=\"" + token + "\", oauth_signature=\"" + appsecret + "&" + token_secret + "\"";
    headers = curl_slist_append(headers, header.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    curl_easy_setopt(curl, CURLOPT_PUT, 1L);
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_data);
    curl_easy_setopt(curl, CURLOPT_READDATA, rfp);

    res = curl_easy_perform(curl);

    curl_slist_free_all(headers);
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));

    curl_easy_cleanup(curl);
  }

  fclose(rfp);

  return 0;
}
于 2013-06-12T15:56:11.023 回答
0

有人用过liboauthcpp吗?我怀疑我的错误在于我使用 getURLQueryString 的方式。我将 url 传递给这个函数,但我不确定我是否也必须传递数据。不幸的是,这个库没有文档。

于 2013-06-13T16:55:45.767 回答