пятница, 30 марта 2012 г.

Самый простой пример подключения Google Federated Login (OpenID)

Вот он.
Возможно и не самый, но один из самых простых.
Не используем никаких библиотек, с ними еще разбираться нужно.
Это именно пример, он не оформлен в некую законченную структуру, написан прямолинейно.
Так проще разобраться.

Здесь можно запустить тест

Здесь можно скачать
Там два файла:
1. request.php – его запускаем
2. callback.php – получает ответ

Дальнейший текст содержится в комментариях к коду
Файл request.php

<?php
session_start();

function curlRequest ($pUrl, $pParam = array(), $Meth = 'get') {
 $sRes = '';
 $ch = curl_init();
 curl_setopt($ch, CURLOPT_HEADER, 0);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 if ($Meth == 'post') {
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_URL, $pUrl);
  curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($pParam));
 } else {
  curl_setopt($ch, CURLOPT_URL, $pUrl . '?' . http_build_query($pParam));
 }
 $sRes = curl_exec($ch);
 curl_close($ch);
 return $sRes;
}


/*
Сначала получаем GoogleEndPoint - URL, на который будем отправлять запросы и переадресоваваться
*/
$Resp = curlRequest('https://www.google.com/accounts/o8/id');
$wA = array();
preg_match('/<URI>.*URI>/', $Resp, $wA);
$GoogleEndPoint = str_replace('<URI>', '', str_replace('</URI>', '', $wA[0]));


/*
Теперь AssociationData. В этом примере будем хранить их в сессии
*/
if (empty($_SESSION['GoogleAssociationData'])) {

 $aPrm = array();
 $aPrm['openid.ns'] = 'http://specs.openid.net/auth/2.0';
 $aPrm['openid.mode'] = 'associate';
 $aPrm['openid.assoc_type'] = 'HMAC-SHA1';
 $aPrm['openid.session_type'] = 'no-encryption';
 $Resp = curlRequest($GoogleEndPoint, $aPrm);
 $GoogleAssociationData = array();
 $Resp = explode("\n", $Resp);
 foreach ($Resp as $Line) {
  if (!empty($Line)) {
   list($k) = explode(':', $Line);
   $GoogleAssociationData[$k] = str_replace($k . ':', '', $Line);
  }
 }
 $_SESSION['GoogleAssociationData'] = $GoogleAssociationData;
 /*
  Ответ от Google содержит все то, что мы отправляли в запросе плюс:
  $GoogleAssociationData['assoc_handle'] - Handle, который теперь связывает 
  наш сайт и Google, по сути токен
  $GoogleAssociationData['expires_in'] - время жизни assoc_handle в секундах.
  Время это довольно большое около 13 часов.
  Если возникнет необходимость оптимизировать приложение, сократить количество 
  выдаваемых запросов, то можно сохранить эти данные где нибудь в базе данных 
  или файле и использовать в течение срока их жизни. 
  В этом примере будем просто хранить их в сесии.
  $GoogleAssociationData['mac_key'] - ключ для проверки электронной подписи 
  (параметр №3 в функции hash_hmac)
  Когда callback.php получит от Google данные, необходимо будет проверить их 
  аутентичность.
   Есть два метода сделать это:
   1. Посчитать электронную и сравнить с той, что пришла. Тут понадобится mac_key
   2. Отправить данные на проверку в Google. Для этого есть специальный 
   запрос "check_authentication"
   В этом примере используется метод №2, так что mac_key нам не понадобится
 */

} else {
 $GoogleAssociationData = $_SESSION['GoogleAssociationData'];
}



/*
Теперь подготовим параметры и переадресуем пользователя на страницу авторизации Google
*/
$aPrm = array();
$aPrm['openid.ns'] = 'http://specs.openid.net/auth/2.0';
$aPrm['openid.claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
$aPrm['openid.identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
$aPrm['openid.mode'] = 'checkid_setup';

// Наш assoc_handle
$aPrm['openid.assoc_handle'] = $GoogleAssociationData['assoc_handle'];

// URL для callback.php
$aPrm['openid.return_to'] = 'http://' . $_SERVER['HTTP_HOST'] . 
 str_replace('request', 'callback', $_SERVER['REQUEST_URI']);

// На странице авторизации, рядом с Вашим доменом будет отображаться favicon с Вашего сайта
$aPrm['openid.ns.ui'] = 'http://specs.openid.net/extensions/ui/1.0';
$aPrm['openid.ui.icon'] = 'true';

// Перечень того, что мы хотим получить
$aPrm['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0';
$aPrm['openid.ax.mode'] = 'fetch_request';
$aPrm['openid.ax.required'] = 'country,email,firstname,lastname,language';
$aPrm['openid.ax.type.country'] = 'http://axschema.org/contact/country/home';
$aPrm['openid.ax.type.email'] = 'http://axschema.org/contact/email';
$aPrm['openid.ax.type.firstname'] = 'http://axschema.org/namePerson/first';
$aPrm['openid.ax.type.lastname'] = 'http://axschema.org/namePerson/last';
$aPrm['openid.ax.type.language'] = 'http://axschema.org/pref/language';

// Переадресовываем
header('Location: ' . $GoogleEndPoint . '?' . http_build_query($aPrm));

/*
ВНИМАНИЕ !
На странице авторизации Google есть checkbox "Запомнить"
Погасите его и по пробуйте сначала с выключенным "запомнить", а потом со включенным.
Так будет интереснее
*/

?>


Файл callback.php
<?php
session_start();
$GoogleAssociationData = $_SESSION['GoogleAssociationData'];


function curlRequest ($pUrl, $pParam = array(), $Meth = 'get') {
 $sRes = '';
 $ch = curl_init();
 curl_setopt($ch, CURLOPT_HEADER, 0);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
 if ($Meth == 'post') {
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_URL, $pUrl);
  curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($pParam));
 } else {
  curl_setopt($ch, CURLOPT_URL, $pUrl . '?' . http_build_query($pParam));
 }
 $sRes = curl_exec($ch);
 curl_close($ch);
 return $sRes;
}


echo '<!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body>';


if ($_GET['openid_mode'] == 'id_res') {

 echo '<h3>Пользователь нажал "Да"</h3>';

 /*
 Наш ли это assoc_handle ?
 */
 if ($GoogleAssociationData['assoc_handle'] === $_GET['openid_assoc_handle']) { // Наш

  // Это URL для запроса "check_authentication"
  $CheckEndPoint = $_GET['openid_op_endpoint'];

  /*
  Готовим параметры и выполняем запрос "check_authentication"
  */
  $aPrm = array();
  $aPrm['openid.mode'] = 'check_authentication';
  $aPrm['openid.assoc_handle'] = $_GET['openid_assoc_handle'];
  $aPrm['openid.sig'] = $_GET['openid_sig'];
  $aPrm['openid.signed'] = $_GET['openid_signed'];
  $aSigned = explode(',', $_GET['openid_signed']);
  foreach ($aSigned as $sItem) {
   $aPrm['openid.' . $sItem] = $_GET['openid_' . str_replace('.', '_', $sItem)];
  }
  $Resp = curlRequest($CheckEndPoint, $aPrm, 'post');


  /*
  Если ответ is_valid:true значит все правильно
  */
  if (preg_match('/.*is_valid:true.*/', $Resp)) {

   echo '<h3>Аутентичность данных подтверждена</h3>';

   echo '<h3>Данные пользователя</h3>';
   echo '<p>E-mail: ' . $_GET['openid_ext1_value_email'] . '</p>';
   echo '<p>Имя: ' . $_GET['openid_ext1_value_firstname'] . ' ' . 
    $_GET['openid_ext1_value_lastname'] . '</p>';
   echo '<p>Язык: ' . $_GET['openid_ext1_value_language'] . '</p>';

  } else {
   echo '<h3>Аутентичность данных не подтверждена</h3>';
  }

 } else {
  echo '<h3>Не верный (не наш) association handle</h3>';
 }

} elseif ($_GET['openid_mode'] == 'cancel') {
 echo '<h3>Пользователь нажал "Нет"</h3>';
} else {
 echo '<h3>Другой (не Ok) статус: ' . $_GET['openid_mode'] . '</h3>';
}


echo '<p><a href="http://alexhpm.rupai.net/googleopenid/request.php">Запустить еще раз</a></p>';
echo '</body></html>';
?>


Документация от Google находится здесь

Комментариев нет:

Отправить комментарий