April 24, 2011
OpenID

Дошли руки до разборок с OpenID. Цель - прикрутить OpenID в качестве альтернативы регистрации/входу в проекте на Symfony2 PR4 (все некогда портировать на более новую версию).

Решил пойти стандартным в таких ситуациях путём:

  1. почитал что такое OpenID;
  2. нашел простую и работающую библиотеку (не самому же писать :3);
  3. оформил в виде бандла к фреймворку, чтобы можно было использовать в других проектах (только разницу между pr4 и версией фреймворка нового проекта учесть, а это - мелочи).

Основы OpenID

OpenID делается в 3 основных шага:

  1. Сгенерить URL, на который отправить пользователя для того, чтобы он подтвердил отправку своих данных;
  2. Получить данные (после подтверждения пользователя перебрасывают обратно к нам с кучей GET-параметров информации);
  3. Теневым запросом провайдеру OpenID проверить полученные данные (дабы юзер не наебал нас изменил данные, подменив GET запрос к нашей странице).

Первый шаг довольно просто пройти. От пользователя мы получаем его OpenID идентификатор, например, blablabla.livejournal.com. Используя этот идентификатор, с помощью Yadis discovery получаем URL провайдера, на который надо редиректнуть пользователя. Добавляем к полученному URLу параметров, где указываем информацию, которую хочется получить (мыло, имя…).

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

После этого необходимо проверить полученные данные, послав теневой check_authentication запрос по ранее полученному URLу и отпарсить ответ.

В качестве готового решения был выбран простой как грабли класс LightOpenID by Mewp.

После этого - довольно легко был написан бандл (ознакомится с кодесом можно на гитхабе), который отдает сервис с методами start и finish. start реализует шаг 1, finish - получает и проверяет полученную от OpenID провайдера информацию, а также возвращает массив полученной информации (мыло, имя…).

При этом использование сервиса становится тривиальным.

/**
	 * Example Action that sends OpenID request
	 * and recieves returned attributes
	 * @uses OpenIDService::start()
	 * @uses OpenIDService::finsh()
	 */
	public function showAction()
	{
		/*
		 * Get OpenIDService
		 */
		$oid = $this->get('openid');
		
		/*
		 * If it is first user request
		 */
		if (count($_GET) == 0)
		{
			/*
			 * Redirect user to provider's authentification page
			 */
			$resp = $oid->start();
			if ($resp) return $resp;
			
			/*
			 * Or just die on error
			 */
			die('Invalid ID or another error happened');
		} else {
			
			/*
			 * When OpenID provider returned parameters via _GET
			 *  check them and show
			 */
			$attributes = $oid->finish();
			if ($attributes) 
			{
				var_dump($attributes);
				die();	
			}
			
			/*
			 * Or just die on error
			 */
			die('User canceled request or another error happened (validation failed, etc...)');
		}
	}

А вся настройка производится в конфигфайле:

# An example of ur config.yml:
#openid.config: 
#    openid:
#        required:
#            email: "contact/email" 			# required mail 
#            first: "namePerson/first"		# and first name from OpenID provider
#								# ...other required parameters
#        return: "openid"				# name of return_to route
#								# if not set - returned to the same url that sent the request
#        default: "google.com/accounts/o8/id"  # default identity is google one
#    

  1. ziumin posted this