Почему я получаю HTTP 401 Unauthorized при вызове API контактов Yahoo?

Это сводит меня с ума. Я реализую схему приглашения друзей на веб-сайте, и мне нужен доступ к списку контактов Yahoo пользователя. Для этого я использую OAuth и REST API Yahoo. Вот полное изложение последовательности событий:

У меня есть проект, созданный на сайте developer.yahoo.com, который настроен на доступ для чтения к контактам. Он находится в выдуманном домене, на который я указываю 127.0.0.1 в файле hosts (на случай, если локальный хост был причиной моих бед). По этой причине домен не проверен, хотя я понимаю, что это просто означает, что у меня меньше ограничений, а не больше.

Во-первых, на сервере я получаю токен запроса:

https://api.login.yahoo.com/oauth/v2/get_request_token
    ?oauth_callback=http%3A%2F%2Fdev.mysite.com%2Fcallback.aspx
    &oauth_consumer_key=MYCONSUMERKEY--
    &oauth_nonce=xmaf8ol87uxwkxij
    &oauth_signature=WyWWIsjN1ANeiRpZxa73XBqZ2tQ%3D
    &oauth_signature_method=HMAC-SHA1
    &oauth_timestamp=1328796736
    &oauth_version=1.0

Что возвращается с (отформатировано для расплывчатой ​​​​попытки ясности):

oauth_token=hxcsqgj
&oauth_token_secret=18d01302348049830942830942630be6bee5
&oauth_expires_in=3600
&xoauth_request_auth_url
    =https%3A%2F%2Fapi.login.yahoo.com%2Foauth%2Fv2%2Frequest_auth
     %3Foauth_token%3Dhxcsqgj
&oauth_callback_confirmed=true"

Затем я открываю пользователю страницу xoauth_request_auth_url и получаю код проверки на свою страницу обратного вызова. Затем я отправляю это обратно на свой сервер, чтобы обменять его на токен доступа:

https://api.login.yahoo.com/oauth/v2/get_token
    ?oauth_consumer_key=MYCONSUMERKEY--
    &oauth_nonce=yxhd1nymwd03x189
    &oauth_signature=c%2F6GTcybGJSQi4TOpvueLUO%2Fgrs%3D
    &oauth_signature_method=HMAC-SHA1
    &oauth_timestamp=1328796878
    &oauth_token=hxcqgjs
    &oauth_verifier=b8ngvp        <- verifier given via callback
    &oauth_version=1.0

Кажется, это работает, и я получаю токен доступа:

oauth_token=MYVERYLONGACCESSTOKEN--
&oauth_token_secret=MYOATHTOKENSECRET
&oauth_expires_in=3600
&oauth_session_handle=ADuXM093mTB4bgJPKby2lWeKvzrabvCrmjuAfrmA6mh5lEZUIin6
&oauth_authorization_expires_in=818686769
&xoauth_yahoo_guid=MYYAHOOGUID

Затем я немедленно пытаюсь получить список контактов с токеном доступа и GUID:

http://social.yahooapis.com/v1/user/MYYAHOOGUID/contacts

(HTTP Header added and formatted with line breaks for clarity...)

Authorization: OAuth
    realm="yahooapis.com",
    oauth_consumer_key="MYCONSUMERKEY--",
    oauth_nonce="nzffzj5v82mgf4mx",
    oauth_signature="moVJywesuGaPN5YHYKqra4T2ips%3D",
    oauth_signature_method="HMAC-SHA1",
    oauth_timestamp="1328796907",
    oauth_token="MYVERYLONGACCESSTOKEN--",
    oauth_version="1.0"

От этого звонка я получаю 401 Unauthorized, но, кажется, невозможно выяснить, почему. Чтобы подписать эти вызовы, я использую эту библиотеку присяги на github. Я не думаю, что это делает что-то экстраординарное или несовместимое. Для подписи я включаю ключ/секрет потребителя и токен/секрет доступа. Я просмотрел базу сигнатур, которая хэшируется, и похоже, что она имеет ту же форму, что и примеры, видимые в документации Yahoo. Я предполагаю, что мне не хватает чего-то из параметров, которые не хэшируются. Есть ли способ выяснить, почему вызов является несанкционированным, или кто-нибудь знает пример, показывающий, какую именно форму должны принимать база подписи и заголовок авторизации?


person izb    schedule 09.02.2012    source источник
comment
http://oauth.net/core/1.0a/#http_codes   -  person Jesvin Jose    schedule 10.02.2012
comment
Привет, izb, я следую инструкциям в developer.yahoo.com/oauth/ guide/oauth-auth-flow.html, но я застрял на шаге 4 (замените токен запроса и верификатор OAuth на токен доступа). Когда я создаю URL-адрес для получения токена доступа, я получаю сообщение об ошибке irefox не может найти файл по адресу api.login.yahoo.com/oauth/v2/get_token?oauth_consumer_key=........, пожалуйста, помогите мне.   -  person Gia Duong Duc Minh    schedule 01.03.2013


Ответы (2)


Решил это сам. Добавление ответа на всякий случай поможет любому, кто совершит ту же глупую ошибку, что и я. Когда я сделал вызов API, я использовал секрет токена, возвращенный из исходного вызова токена запроса, вместо нового, возвращенного из вызова токена доступа.

Упс.

person izb    schedule 09.02.2012
comment
Эй, я столкнулся с этой проблемой здесь .. что мы должны использовать в oauth_signature при запросе контактов вместе с oauth_token (токен доступа) - person Nezam; 19.03.2013

это код, с помощью которого я решил, надежный код для использования, если yahooapis возвращает 403 запрещено:

Ссылка: https://developer.yahoo.com/yql/guide/yql-code-examples.html#yql_php https://github.com/danzisi/YQLQueryYahooapis

    init CODE

/**
 * Call the Yahoo Contact API
 *
 * https://developer.yahoo.com/yql/guide/yql-code-examples.html#yql_php
 *
 * @param string $consumer_key obtained when you registered your app
 * @param string $consumer_secret obtained when you registered your app
 * @param string $guid obtained from getacctok
 * @param string $access_token obtained from getacctok
 * @param string $access_token_secret obtained from getacctok
 * @param bool $usePost use HTTP POST instead of GET
 * @param bool $passOAuthInHeader pass the OAuth credentials in HTTP header
 * @return response string with token or empty array on error
 */ 
function call_yql($consumer_key, $consumer_secret, $querynum, $access_token, $access_token_secret, $oauth_session_handle, $usePost=false, $passOAuthInHeader = true){
  global $godebug;
  $response = array();

  if ($consumer_key=='' || $consumer_secret=='' || $querynum=='' || $access_token=='' || $access_token_secret=='' || $oauth_session_handle) return array('0' => 'Forbidden');

  if ($querynum == 1) {
    $url = 'https://query.yahooapis.com/v1/yql';
    // Show my profile
    $params['q'] = 'select * from social.profile where guid=me';
  } elseif ($querynum == 2) {
    $url = 'https://query.yahooapis.com/v1/yql';
    // here other query

  } 

  $params['format'] = 'json';  //json xml
  $params['Authorization'] = 'OAuth';  
  $params['oauth_session_handle'] =  $oauth_session_handle;
  $params['realm'] = 'yahooapis.com';
  $params['callback'] = 'cbfunc';
  $params['oauth_version'] = '1.0';
  $params['oauth_nonce'] = mt_rand();
  $params['oauth_timestamp'] = time();
  $params['oauth_consumer_key'] = $consumer_key;
  $params['oauth_callback'] = 'oob';
  $params['oauth_token'] = $access_token;

  $params['oauth_signature_method'] = 'HMAC-SHA1';
  $params['oauth_signature'] = oauth_compute_hmac_sig($usePost? 'POST' : 'GET', $url, $params, $consumer_secret, $access_token_secret);

  if ($passOAuthInHeader) {
    $query_parameter_string = oauth_http_build_query($params, true);
    $header = build_oauth_header($params, "yahooapis.com");
    $headers[] = $header;
  } else {
    $query_parameter_string = oauth_http_build_query($params);
  }

  // POST or GET the request
  if ($usePost) {
    $request_url = $url;   
    logit("call_yql:INFO:request_url:$request_url");
    logit("call_yql:INFO:post_body:$query_parameter_string");
    $headers[] = 'Content-Type: application/x-www-form-urlencoded';
    $response = do_post($request_url, $query_parameter_string, 443, $headers);
  } else {
    $request_url = $url . ($query_parameter_string ? ('?' . $query_parameter_string) : '' );
    logit("call_yql:INFO:request_url:$request_url");
    $response = do_get($request_url, 443, $headers);
  }

  // extract successful response
  if (! empty($response)) {   
    list($info, $header, $body) = $response;  

    if ($godebug==true) {
        echo "<p>Debug: function call_yql info: <pre>" . print_r($info, TRUE) . "</pre></p>";
        echo "<p>Debug: function call_yql header: <pre>" . print_r($header, TRUE) . "</pre></p>";
        echo "<p>Debug: function call_yql body: <pre>" . print_r($body, TRUE) . "</pre></p>";
    }
    if ($body) {
      $body = GetBetween($body, 'cbfunc(', ')');   
      $full_array_body = json_decode($body);
      logit("call_yql:INFO:response:");  
      if ($godebug==true) echo "<p>Debug: function call_yql full_array_body: <pre>" . print_r($full_array_body, TRUE) . "</pre></p>";
      } 

  }
  // return object 
  return $full_array_body->query;
}
    END code
person Meggis    schedule 26.04.2014