PHP SDK: как получить токен доступа после авторизации пользователя в приложении?

Это для приложения на основе холста на платформе Facebook с использованием нового (самого) Facebook PHP SDK.

Мы используем пример PHP из учебника Facebook (https://developers.facebook.com/docs/appsonfacebook/tutorial/), чтобы вызвать диалоговое окно OAuth и направить тестового пользователя на URL-адрес перенаправления.

В URL-адресе перенаправления мы используем пример PHP со страницы документации подписанного запроса Facebook (https://developers.facebook.com/docs/authentication/signed_request/), и наши тестовые пользователи могут успешно авторизовать приложение.

Однако после того, как тестовый пользователь авторизует приложение, мы не сможем зафиксировать токен доступа и срок его действия. Мы видим его в адресной строке, добавленной к URL-адресу перенаправления, но он не отображается в массиве $_REQUEST. Если мы добавим {$access_token = $facebook->getAccessToken();} на страницу URL-адреса перенаправления, она покажет значение токена доступа, но отображаемое значение не является полной строкой токена, которую мы видим, когда нажимаем Показать Токен на странице ролей тестовых пользователей (мы считаем, что это правильный токен доступа для тестового пользователя).

Вот пример URL-адреса перенаправления с добавленным токеном доступа: -100002908746828%7CJICJwM1P_97tKmqkEO5pXDCf-7Y&expires_in=6008" rel="nofollow">http://karmakorn.com/karmakorn/alpha20/kk-fb-auth.php#access_token=126736467765%7C2.AQDavId8oL80P5t9.3600.1315522800.1-100002908746828%7CJICJwM1P_97tKmqkEO5pXDCf -7Y&expires_in=6008

Вот что показывает var_dump для массива $REQUEST для той же страницы: array(3) { ["_qca"]=> string(26) "P0-709927483-1291994912966" ["__switchTo5x"] => строка (2) "30" ["PHPSESSID"] => строка (26) "euois02ead39ijumca7nffblh2" }

Мы понятия не имеем, почему массив $_REQUEST отличается от значений, добавленных к URL-адресу, и, что более важно, как получить токен доступа и дату его истечения.

Может ли кто-нибудь показать нам рабочий пример того, как они собирают эти данные после запуска функции parse_signed_request($signed_request, $secret) на странице перенаправления? Спасибо!

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ:

Вот соответствующий код из A) нашей тестовой индексной страницы и B) нашей тестовой страницы перенаправления. Если мы используем нашу текстовую индексную страницу в качестве URL-адреса перенаправления, она застревает в бесконечном цикле, потому что пользователь никогда не идентифицируется.

А) Индексная страница

// Create kk-fb app instance
$facebook = new Facebook(array(
    'appId'  => KKFB_ID,
    'secret' => KKFB_KY,
    'oauth' => true,
));

$app_id = KKFB_ID;
$secret = KKFB_KY;
$canvas_auth = 'http://karmakorn.com/karmakorn/alpha20/kk-fb-auth.php';

$auth_url = "https://www.facebook.com/dialog/oauth?" 
                . "client_id=" . $app_id 
                . "&redirect_uri=" . urlencode($canvas_auth) 
                . "&response_type=token" 
                . "&scope=email,publish_stream";

$signed_request = $_REQUEST["signed_request"];

list($encoded_sig, $payload) = explode('.', $signed_request, 2); 

$data = json_decode(base64_decode(strtr($payload, '-_', '+/')), true);

if (empty($data["user_id"])) {
    echo("<script> top.location.href='" . $auth_url . "'</script>");
} else {
    echo ("Welcome User: " . $data["user_id"]);
}

Б) Страница перенаправления

// Create kk-fb app instance
$facebook = new Facebook(array(
    'appId'  => KKFB_ID,
    'secret' => KKFB_KY,
    'oauth' => true,
));

$app_id = KKFB_ID;
$secret = KKFB_KY;

$signed_request = $_REQUEST["signed_request"];

list($encoded_sig, $payload) = explode('.', $signed_request, 2); 

$data = json_decode(base64_decode(strtr($payload, '-_', '+/')), true);

$user = $facebook->getUser();
$access_token = $facebook->getAccessToken();

echo "User: $user <br>";
echo "Access Token: $access_token <br>";
echo "Signed Request: $signed_request <br>";
var_dump($_REQUEST);

Вот что отображается в виде этих эхо-результатов:

Пользователь: 0 Токен доступа: 126736467765|**SECRET** Подписанный запрос: array(3) { ["_qca"]=> string(26) "P0-709927483-1291994912966" ["_switchTo5x"]=> строка(2) "30" ["PHPSESSID"]=> строка(26) "frugi545cdl15gjind1fnv6pq1" }

Интересно, что когда тестовый пользователь возвращается на индексную страницу, условие if выполняется, и мы можем получить правильный токен доступа:

Добро пожаловать, пользователь: 100002908746828 Токен доступа: 126736467765|2.AQBgcyzfu75IMCjw.3600.1315544400.1-100002908746828|m5IYEm976tJAkbTLdxHAhhgKmz8

Очевидно, мы все еще что-то упускаем!? Кроме того, нам нужно научиться получать время истечения срока действия в качестве переменной, чтобы мы могли хранить оба значения в нашей базе данных.


person Bill Scheurer    schedule 08.09.2011    source источник


Ответы (4)


Хорошо, давайте попробуем это снова.

Проверка подлинности на стороне сервера и на стороне клиента

Вы используете исключительно PHP SDK, поэтому хотите выполнить аутентификацию на стороне сервера, где код аутентификации отправляется на сервер по HTTP через URL-адрес. Это позволит вам получить токен доступа для пользователя при загрузке первой страницы после аутентификации (в вашем случае на странице перенаправления). Создаваемый в настоящее время auth_url имеет значение response_type=token, что заставляет перенаправление использовать режим аутентификации на стороне клиента и устанавливать токен во фрагменте URL, а не в запросе. Вы должны полностью удалить этот параметр. На самом деле, я настоятельно рекомендую вам просто использовать PHP SDK вместо того, чтобы создавать этот URL самостоятельно. См. пример ниже.

Токены доступа к приложению

Необычно выглядящий токен доступа 126736467765|SECRET — это токен доступа вашего приложения, который состоит из идентификатора вашего приложения и секретного ключа. Маркер доступа к приложению возвращается функцией getAccessToken(), если маркер доступа пользователя недоступен (поскольку для некоторых вызовов API требуется хотя бы какой-либо маркер доступа). Это также означает, что вы раскрыли свой секретный ключ миру через эту запись в блоге, поэтому вам следует сбросить секрет вашего приложения в противном случае любой сможет совершать вызовы API от вашего имени. Я настоятельно рекомендую вам удалять части ваших токенов доступа, если вы делитесь ими с другими.

Срок действия токена

Поток OAuth 2.0 и версия 3.1.1 PHP SDK не упрощают определение времени истечения срока действия токена. Я бы посоветовал попытаться сделать вызов API, а затем обновить токен, если вызов API завершается с ошибкой OAuthException. Токены могут быть недействительными, даже если срок их действия еще не истек, поэтому это относится к большему количеству случаев. Однако, если вы все еще хотите сохранить дату истечения срока действия на своей стороне, вы можете просто извлечь ее из самого токена. Если у вас есть токен с истекающим сроком действия, отметка времени истечения срока действия будет содержаться в этой строке. Вот функция, которую я быстро собрал, чтобы извлечь это:

function extractExpirationFromToken($access_token) {
    $segments = explode('|', $access_token);
    if(count($segments) < 2) { return 0; }

    $segments = explode('.', $segments[1]);
    if(count($segments) < 4) { return 0; }

    $expires = $segments[3];
    $dash_pos = strrpos($expires, '-');
    if($dash_pos !== false) {
        $expires = substr($expires, 0, $dash_pos);
    }
    return $expires;
}

Код новой индексной страницы

// Create kk-fb app instance
$facebook = new Facebook(array(
    'appId'  => KKFB_ID,
    'secret' => KKFB_KY,
));

$canvas_auth = 'http://karmakorn.com/karmakorn/alpha20/kk-fb-auth.php';

$auth_url = $facebook->getLoginUrl(array(
    'scope' => 'email,publish_stream',
    'redirect_uri' => $canvas_auth, // you could just redirect back to this index page though
));

$user = $facebook->getUser();

if (empty($user)) {
    echo("<script> top.location.href='" . $auth_url . "'</script>");
} else {
    echo ("Welcome User: " . $user);
}

Страница перенаправления

Я не думаю, что вам нужна эта страница вообще. Вы можете просто перенаправить пользователя обратно на исходную индексную страницу.

// Create kk-fb app instance
$facebook = new Facebook(array(
    'appId'  => KKFB_ID,
    'secret' => KKFB_KY,
));

$user = $facebook->getUser();
$access_token = $facebook->getAccessToken();
// also copy the function definition given earlier
$expiration = extractExpirationFromToken($access_token);

echo "User: $user <br>";
echo "Access Token: $access_token <br>";
echo "Expiration: $expiration <br>";
echo "Request: <br>";
var_dump($_REQUEST);
person PCheese    schedule 09.09.2011
comment
ПК, спасибо за продолжение с такими подробными примерами кода. Очень щедро с твоей стороны! Заставляет меня задаться вопросом, почему документы Facebook смущают нас примерами кода signed_request? Во всяком случае, ваш пример позволил мне свернуть это на одну страницу без бесконечного цикла. Однако использование исходной индексной страницы вывело моего тестового пользователя из браузера. Если вместо этого я использую apps.facebook.com, я остаюсь в браузере. Однако URL-адрес адресной строки заполнен информацией о состоянии, которая может отвлекать пользователя. Если вместо этого мы используем 2-страничный процесс, мы получаем чистый URL-адрес. Так что мы можем придерживаться этого. - person Bill Scheurer; 10.09.2011
comment
ПК, ваш опыт и щедрость очень полезны. Буду рад получить от вас приглашение присоединиться к LinkedIn. Счет - person Bill Scheurer; 10.09.2011

Например, вы можете использовать сборку facebook в методе getAccessToken();

$access_token = $facebook->getAccessToken();

Это даст вам токен доступа к вашей переменной, теперь, если вы получаете его пустым, не забудьте сначала проверить, правильно ли ловится fuid, если это не так, вам может потребоваться просмотреть свои настройки, убедитесь, что ваш «Домен приложения» установлена, эта часть очень важна, после правильной настройки вам необходимо сбросить секрет приложения, а затем установить новые значения в коде аутентификации. Надеюсь, это поможет, дайте мне знать :)

пд. Также не забудьте сохранить видимость области ваших переменных во всем вашем php-файле или классе.

person Joe Walker    schedule 08.09.2011

Проблема

access_token во вставленном URL-адресе не является частью строки запроса, а содержится во фрагменте URL-адреса (после #). Фрагменты URL-адресов не отправляются на веб-сервер и доступны для чтения только клиентскому коду, такому как Javascript. Поэтому PHP SDK видит только http://karmakorn.com/karmakorn/alpha20/kk-fb-auth.php, поэтому $_REQUEST не содержит ключа access_token.

Вопросы/Примечания

  1. Что вы используете для своего redirect_uri? Я думаю, вы хотите использовать что-то вроде http://apps.facebook.com/your_canvas_url/.
  2. Вам не нужно звонить parse_signed_request самостоятельно или копировать какой-либо код со страницы подписанного запроса. PHP SDK сделает это за вас. Просто позвони:

    $facebook = new Facebook(array(
        'appId' => '…',
        'secret' => '…',
    ));
    $access_token = $facebook->getAccessToken();
    

Возможные решения

  1. Также используйте Facebook Javascript SDK. Вы можете начать с добавления его тега <script> на целевую страницу (kk-fb-auth.php) (см. документы для получения полной информации; не забудьте установить oauth: true). JS SDK должен установить файл cookie (с именем fbsr_126736467765), который PHP SDK сможет прочитать через $_REQUEST или $_COOKIE при последующих загрузках страницы.
person PCheese    schedule 09.09.2011
comment
ПК, спасибо за полезное различие между строкой запроса и фрагментами URL-адреса (о чем нам придется узнать больше). Я добавил некоторые детали к нашему вопросу. Нам бы очень хотелось полностью решить эту проблему с помощью PHP, так как наше приложение интенсивно использует данные, а Facebook JavaScript SDK показывает слишком большую задержку для наших целей — нам нужно заполнить страницы нашего приложения большим количеством данных из нашей базы данных. после того, как мы получим идентификатор Facebook для текущего пользователя. - person Bill Scheurer; 09.09.2011

Если вы хотите сделать это с помощью PHP, вы можете получить токен доступа пользователя с помощью отдельного вызова API Graph в вашем redirect_uri. Для этого вам нужно изменить response_type вашего $auth_url на вашей индексной странице на «code» или «code token».

Затем на вашей странице перенаправления Facebook добавит параметр «код» в строку запроса. Этот вызов API вернет вам полный access_token и время истечения срока действия:

https://graph.facebook.com/oauth/access_token?
    client_id=YOUR_APP_ID&
    redirect_uri=YOUR_URL&
    client_secret=YOUR_APP_SECRET&
    code=$_REQUEST['code']

Дополнительную информацию можно найти в документах по аутентификации.

person Gigablah    schedule 09.09.2011
comment
Gig, для этого нам нужно получить действительный uid Facebook для тестового пользователя. Проблема в том, что наша страница перенаправления продолжает получать uid 0 после того, как тестовый пользователь авторизует приложение. Интересно, связано ли это с какой-то проблемой с задержкой на серверах Facebook? Пока нам не удастся получить действительный uid на нашей странице перенаправления, кажется, что альтернативные способы получения токена доступа являются спорными. Может быть, нам нужно решить проблему с задержкой, перенаправляя на еще одну страницу, чтобы получить uid? Как отмечалось выше, при возврате на страницу индекса тестовый пользователь получает действительный uid. - person Bill Scheurer; 09.09.2011
comment
Билл, причина, по которой вы получаете uid=0, заключается в том, что, как предполагает Гигабла, параметр response_type=token фактически не позволяет серверу получать необходимые ему данные. Этот подход работает только с JS SDK. При использовании PHP вам необходимо сначала получить код авторизации, а затем получить токен доступа самостоятельно. См. мой последний ответ. Я думаю, что JS устанавливает файл cookie из фрагмента URL-адреса при загрузке страницы, поэтому вы видите только пользователя, вошедшего в систему, при последующих запросах страницы. - person PCheese; 10.09.2011