авторизация приложений и схема подписи данных на базе OAuth 2.0

Social networks and communities
При написании большинства приложений на платформе Facebook разработчику требуется получить доступ к данным пользователя: список друзей, ньюсфиды, ссылки, likes и т. д. Разумеется, такую информацию нужно передавать, убедившись что она попадет к нужному получателю от определенного отправителя. Для этого FB предлагает использовать разработанную ими схему подписи на базе OAuth 2.0.

Данные о текущем пользователе (или о текущем профиле) FB передает в параметре signed_request, а именно:
  • algorithm — HMAC-SHA256;
  • user_id — айди текущего пользователя;
  • oauth_token — зашифрованная строка, которую можно использовать в дальнейшем для доступа к Graph API, Old Rest API или FQL;
  • expires — когда истекает oauth_token;
  • profile_id — появляется на табе профиля.

$_REQUEST['signed_request'] представляет собой конкатенацию подписи HMAC SHA-256, точки (.) и JSON объекта, упакованного в base64url. Выглядит примерно так (все слитно):

g2LAGH9BQ25BqO8-V5lP4Z74_DQ7U6AzWDGBpz-3yDg
.
eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjAsIm9hdXRoX3Rva2VuIjoiMTI4ODI1OTA3MTYxMTc3fGNlNmM1NTUwNDEyNDlhOGU4NjlmOTVlOC0xMDAwMDEzMzM0ODk4ACR8ZVRzd1d4WjR5b2pkQ2dHU0dUcWx0NFpvBXlBLiIsInVzZXJfaWQiOiIxMDAwMDEzMzM0ODk4NDQifQ

Для того, чтобы FB передавал нашему приложению signed_request, нужно указать это в настройках (т.к. на данный момент это бета фича):



После того, как пользователь разрешит доступ приложения к своим данным, мы будем получать signed_request в каждом запросе к нашему Canvas URL (откуда FB берет контент приложения). Есть несколько способов вызова такого диалога:

1. Редирект.


Редиректим пользователя на адрес:

https://graph.facebook.com/oauth/authorize?
client_id=наш Application ID
&redirect_uri=куда перейти после разрешения доступа
&scope=какие права запрашивать

Список возможных прав можно найти тут. Если пользователь разрешит доступ, к нам на redirect_uri прийдет нужный signed_request.

2. FBJS метод Facebook.showPermissionDialog.


Например (при разработке FBML приложения):

Facebook.showPermissionDialog('publish_stream,read_stream', callback);

В данном случае нам покажется стандартный FB диалог с запросом прав. В случае разрешения доступа вызовется callback('publish_stream,read_stream'), в противном случае — callback(null);

3. Ajax.


В FBJS есть объект Ajax, и в нем — свойство requireLogin. Если при запросе его выставить в true — ajax запрос будет успешным только после разрешения юзером доступа к своим данным. Например:

var ajax = new Ajax();
ajax.responseType = Ajax.FBML;
ajax.ondone = function(data) {
	console.log(data);
}
ajax.requireLogin = true;
ajax.post("http://example.com/processAjax.php");

Здесь, как и в предыдущем способе, вызовется FB диалог. FBJS во многом ограничивает разработчика, в частности после парсинга нашего FBML ко всем переменным и функциям добавляется строка appAPPLICATIOPN_ID_, т. е. var ajax превращается в var app1234567890_ajax, alert — в app1234567890_alert. Хорошо есть console, фактически основной дебаггер. В будущем FB планирует отказаться от FBML приложений в пользу айфреймов и Javascript SDK, чем существенно упростит разработку приложений на табах.

4. Javascript SDK


После инициализации приложения нужно вызвать метод FB.login:
FB.login(function(response) {
  if (response.session) {
    // user successfully logged in
  } else {
    // user cancelled login
  }
});

Диалог покажется в попапе браузера.

Во всех случаях появится примерно такой диалог:



Получив signed_request, его нужно распарсить. FB предлагает так (ф-ции включены в PHP SDK):

function parse_signed_request($signed_request, $secret) {    // $secret - Application Secret
  list($encoded_sig, $payload) = explode('.', $signed_request, 2); 

  // decode the data
  $sig = base64_url_decode($encoded_sig);
  $data = json_decode(base64_url_decode($payload), true);

  if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
    error_log('Unknown algorithm. Expected HMAC-SHA256');
    return null;
  }

  // check sig
  $expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
  if ($sig !== $expected_sig) {
    error_log('Bad Signed JSON signature!');
    return null;
  }

  return $data;
}

function base64_url_decode($input) {
  // $input - base64url
  return base64_decode(strtr($input, '-_', '+/'));
}

Функция parse_signed_request вернет нам ассоциативный массив, одним из ключей которого будет oauth_token. Далее можно использовать токен для доступа к Graph API, Old Rest API или FQL. Например:

Друзья: https://graph.facebook.com/ID/friends?access_token=...
Ньюсфиды: https://graph.facebook.com/ID/home?access_token=...
Стена: https://graph.facebook.com/ID/feed?access_token=...

При разработке FBML приложения на табе есть одна особенность: после разрешения пользователем доступа, получить signed_request с user_id можно только с ajax-запроса. В противном случае user_id будет равен profile_id (оба — айди текущего профиля (страницы)), и oauth_token будет «прикреплен» к странице, а не к профилю юзера.

Удачи!
Tags:facebook apioauth 2.0signed request
Hubs: Social networks and communities
+29
5.2k 72
Comments 16

Popular right now

Software Engineer (Java + JS)
from 130,000 to 165,000 ₽GenesysСанкт-ПетербургRemote job
Middle Java Developer (Краснодар)
from 90,000 ₽ТagesJumpКраснодар
Senior Backend Developer (PHP/Go)
from 300,000 to 320,000 ₽SmartTel PlusВаршаваRemote job
Senior iOS Developer (приложение KazanExpress)
from 160,000 ₽KazanExpressИннополис