Как «подружить» сервис Loginza и фреймворк Yii

Владимир | | PHP, Web разработка, Yii.

loginza yii

Постоянные читатели этого блога, наверное, помнят, что и о фреймворке Yii, и о сервисе аутентификации Loginza я раньше рассказывал. Найти эти статьи несложно: Yii, Loginza.

Но в статье о Loginza, речь шла о протоколе обмена данными с сервисом, а вопрос аутентификации остался «за бортом». Я, конечно, объяснил когда нужно создавать сессию, но на практике этого явно недостаточно 😉

В этой статье я постараюсь исправить этот недостаток и покажу пример аутентификации пользователя с помощью сервиса Loginza.

Прежде всего, определим требования к такой системе.

1) Она не должна нарушать работу стандартной системы аутентификации (с использованием логина и пароля).

2) Должны поддерживаться стандартные средства Yii для работы с пользователями. Речь о компоненте Yii::app()->user (CWebUser).

3) Завершение сеанса (Yii::app()->user->logout()) должно работать независимо от того каким образом была выполнена аутентификация.

4) Если посетитель впервые зашел на сайт и успешно прошел аутентификацию с помощью Loginza, для него нужно автоматически создать аккаунт.

5) Нужна возможность удобно показывать ссылку «Войти с помощью Loginza» на любой странице сайта (виджет).

6) После аутентификации пользователь должен вернуться на исходную страницу.

Чтобы лучше представить фронт работ, рассмотрим алгоритм аутентификации фреймворка Yii.

1. Посетитель кликает по кнопке «Войти с помощью Loginza».

2. Появляется виджет в котором пользователь выбирает сервис аутентификации.

3. Loginza проводит аутентификацию и возвращает посетителя на наш сайт. При этом в массиве $_POST передается token, с помощью которого можно получить результаты аутентификации пользователя.

4. Наше приложение должно.

4.1. Получить данные от сервиса Loginza.

4.2. Создать пользователя (экземпляр класса, реализующий интерфейс IUserIdentity). Этот класс содержит метод authenticate в котором мы проверим, существует ли данный пользователь в БД, если нет – создадим его, и установим данные, которые необходимы для работы класса CWebUser.

4.3. Выполнить аутентификацию. Т.е. вызвать Yii::app()->user->login. При этом в первом параметре метода login мы передаем экземпляр класса, реализующего IUserIdentity (который мы создали на предыдущем этапе). Таким образом, мы обеспечим нормальную работу нашего класса со всеми остальными компонентами фреймворка.

Переходим к реализации.

Шаг 1. Создадим виджет, показывающий ссылку «Войти с помощью Loginza».

Он будет состоять из двух файлов:
1) protected/components/LoginzaWidget.php – класс виджета
2) protected/components/views/loginzaWidget.php – представление.

Рассмотрим класс виджета.

<?php
class LoginzaWidget extends CWidget {
	//параметры по-умолчанию
	private $params = array(
		'widget_url'=>'https://s3-eu-west-1.amazonaws.com/s1.loginza.ru/js/widget.js',
		'token_url'=>'https://loginza.ru/api/widget?token_url=',
		'return_url'=>'',
		'link_anchor'=>'Войти с помощью Loginza',
		'logout_url'=>'',
		'css_class'=>'loginza',
		'providers_set'=>array('vkontakte', 'facebook', 'twitter', 'loginza'
            , 'myopenid', 'webmoney', 'rambler', 'flickr', 'lastfm', 'openid'
            , 'mailru', 'verisign', 'aol', 'steam', 'google', 'yandex'
            , 'mailruapi'),
	);

	/**
	 * Этот метод подключает JS скрипт и загружает представление
	 */
    public function run() {
        //подключаем JS скрипт
        Yii::app()->clientScript->registerScriptFile(
				$this->params['widget_url']
                , CClientScript::POS_END);
        $this->render('loginzaWidget', $this->params);
    }

	/**
	 * Установка параметров
	 * @param array $params массив с параметрами
	 */
	public function setParams($params) {
		$this->params = array_merge($this->params, $params);
	}
}

Здесь мы создаем массив с дефолтными параметрами, в котором указываем настройки, необходимые для работы с сервисом Loginza. Подробно на них останавливаться не будем, т.к. они рассмотрены в предыдущей статье. Но обратите внимание, что обязательно нужно установить два параметра: return_url и logout_url.

В первом (return_url) нужно указать адрес, на который должен быть перенаправлен пользователь после аутентификации на Loginza.

Во втором (logout_url) – адрес метода, выполняющего завершение сессии.

Эти методы выполняют непосредственно аутентификацию пользователя в нашем приложении, и логично, что виджет о них ничего не знает.

Таким образом, подключить виджет можно так.

<?php  $this->widget('application.components.LoginzaWidget', array(
	'params'=>array(
		'return_url'=>'site/loginzalogin',
		'logout_url'=>'site/logout',
		'providers_set'=>array('google','vkontakte','facebook','twitter','rambler','openid','mailru','yandex','mailruapi'),
	),
)); ?>

В представлении (protected/components/views/loginzaWidget.php) мы проверяем, аутентифицирован ли пользователь и в зависимости от результата выводим ссылку «Войти с помощью Loginza» или «Выход».

<?php if (Yii::app()->user->isGuest) {
	$url = $token_url.Yii::app()->createAbsoluteUrl($return_url
			, array('providers_set'=>implode(',',$providers_set)));
	echo CHtml::link($link_anchor, $url, array('class'=>$css_class));
} else {
	$anchor = 'Выйти ('.Yii::app()->user->getName().')';
	echo CHtml::link($anchor, array($logout_url));
}
?>

Шаг 2. Напишем метод, выполняющий аутентификацию посетителя.

Я добавил этот метод в класс SiteController, который автоматически создается утилитой yiic при создании приложения.

public function actionLoginzaLogin() {
	//проверяем, пришел ли token
	if (isset($_POST['token'])) {
		$loginza = new LoginzaModel();
		$loginza->setAttributes($_POST);
		$loginza->getAuthData();
		if ($loginza->validate() && $loginza->login()) {
			//возвращаем пользователя на ту страницу на которой он
			//находился перед аутентификацией
			$this->redirect(Yii::app()->user->returnUrl);
		}
		else {
			//сообщение об ошибке
			$this->render('loginzaerror');
		}
	}
	else {
		//если этот метод вызван напрямую (без указания token)
		$this->redirect(Yii::app()->homeUrl, true);
	}
}

Этот метод мы указали в параметре return_url при настройке виджета, таким образом, именно на него придет редирект от сервиса Loginza.

Мы проверяем наличие параметра token в массиве $_POST и если он найден, продолжаем процедуру аутентификации.

От Loginza мы получаем данные о результатах аутентификации, и проверить их будет совсем не лишним. Мы, конечно, можем написать весь код самостоятельно, но гораздо удобнее использовать встроенные средства фреймворка.

Шаг 3. Создаем модель, выполняющую обработку данных от Loginza.

Модель будет называться LoginzaModel, но прежде чем переходить к ее детальному рассмотрению, определимся, какие данные о пользователе нужно хранить в БД.

Loginza передает в обязательно порядке два параметра: identity и provider (именно они позволяют однозначно идентифицировать пользователя), остальные зависят от выбранного сервиса аутентификации.

Кроме того, полезно будет хранить email пользователя и его имя. К сожалению, в зависимости от сервиса вы можете получить эти данные, а можете и не получить 🙂

Теперь рассмотрим сам класс.

<?php
class LoginzaModel extends CModel {

	public $identity;
	public $provider;
	public $email;
	public $full_name;
	public $token;
	public $error_type;
	public $error_message;

	private $loginzaAuthUrl = 'http://loginza.ru/api/authinfo?token=';

	public function rules() {
		return array(
			array('identity,provider,token', 'required'),
			array('email', 'email'),
			array('identity,provider,email', 'length', 'max'=>255),
			array('full_name', 'length', 'max'=>55),
		);
	}

	public function attributeLabels() {
		return array(
			'identity'=>'Идентификатор сервиса аутентификации',
			'provider'=>'Сервис аутентификации',
			'email'=>'eMail',
			'full_name'=>'Имя',
		);
	}

	/**
	 * Получение данных от сервиса Loginza.
	 * Предварительно нужно установить $this->token
	 * Например, так
	 * $loginza = new LoginzaModel();
	 * $loginza->setAttributes($_POST);
	 */
	public function getAuthData() {
        //получаем данные от сервера Loginza
        $authData = json_decode(
				file_get_contents($this->loginzaAuthUrl.$this->token)
				,true);

		//устанавливаем атрибуты
		//если будут отсутствовать identity и provider, метод validate
		//выдаст ошибку
		$this->setAttributes($authData);
		//full_name находится внутри вложенного массива
		//TODO доделать установку имени для разных сервисов
		$this->full_name = (isset($authData['name']['full_name'])) ? $authData['name']['full_name'] : $authData['identity'];
	}

	/**
	 * Аутентификация посетителя.
	 * @return boolean true - если посетитель аутентифицирован, false - в противном случае.
	 */
	public function login() {
		$identity = new LoginzaUserIdentity();
		if ($identity->authenticate($this)) {
			$duration = 3600*24*30; // 30 days
			Yii::app()->user->login($identity,$duration);
			return true;
		}
		return false;
	}

	public function attributeNames() {
		return array(
			'identity'
			,'provider'
			,'email'
			,'full_name'
			,'token'
			,'error_type'
			,'error_message'
		);
	}
}

Обратите внимание, что мы наследуем его от CModel и, таким образом, получаем возможность использовать встроенные средства проверки данных. Т.е. мы просто объявляем метод rules, который возвращает массив с правилами проверки.

Метод getAuthData отправляет запрос серверу Loginza, обрабатывает результат и устанавливает значения атрибутам этого класса.

Вы, наверное, заметили, что установка имени пользователя немного не доделана. Дело в том, что сервисы передают эти данные в разных элементах массива. Элемент full_name устанавливает Google. По большому счету, нужно просмотреть данные, которые возвращают остальные сервисы и соответственно устанавливать $this->full_name.

Метод login в случае успешной аутентификации создает сессию для пользователя. В нём мы создаем экземпляр класса LoginzaUserIdentity, который реализует интерфейс IUserIdentity, и передаем его в первом параметре Yii::app()->user->login.

Также LoginzaUserIdentity содержит метод authenticate, который выполняет поиск пользователя в БД и, в случае необходимости, создает новый аккаунт.

В зависимости от результата, метод login возвращает true или false.

Прежде чем переходить к рассмотрению LoginzaUserIdentity, создадим таблицу в БД в которой будем хранить данные пользователей и классы, необходимые, для работы с ней.

Шаг 4. Создаем таблицу User

Тут все просто.

Для создания таблицы можно использовать следующий SQL запрос

CREATE  TABLE IF NOT EXISTS `tablename`.`user` (
  `u_id` INT NOT NULL AUTO_INCREMENT ,
  `u_identity` VARCHAR(255) NOT NULL ,
  `u_provider` VARCHAR(255) NOT NULL ,
  `u_email` VARCHAR(255) NULL ,
  `u_full_name` VARCHAR(55) NULL ,
  `u_state` TINYINT(1) NOT NULL ,
  PRIMARY KEY (`u_id`) )
ENGINE = InnoDB;

А классы, необходимые для выполнения CRUD, можно создать с помощью компонента gii.

Вызывается так.
sitename.domen/index.php?r=gii

Предварительно нужно активировать его в настройках приложения (config/main.php)

'modules'=>array(
	'gii'=>array(
		'class'=>'system.gii.GiiModule',
		'password'=>'yourpass',
	),
),

Шаг 5. Создаем класс LoginzaUserIdentity.

Размещаться он будет в protected/components.

Как я уже упоминал, он реализует интерфейс IUserIdentity и, таким образом, фреймворк сможет с ним работать.

<?php
/**
 * Этот класс выполняет аутентификацию и, при необходимости, регистрацию посетителя.
 */
class LoginzaUserIdentity implements IUserIdentity {

	private $id;
	private $name;
	private $isAuthenticated = false;
	private $states = array();

	public function __construct() {
	}

	/**
	 * Аутентификация пользователя.
	 * Этот метод ищет пользователя в БД. Если он не найден, создает нового.
	 * Устанавливает значения атрибутов.
	 *
	 * @param LoginzaModel $loginzaModel модель, содержащая данные от сервиса Loginza
	 * @return boolean true если пользователь найден или создан новый аккаунт, false - если недостаточно данных
	 */
	public function authenticate($loginzaModel = null) {

		if (empty($loginzaModel->identity) || empty($loginzaModel->provider)) {
			return false;
		}
        //сначала проверяем, существует ли такой пользователь в БД
        $criteria=new CDbCriteria;
        $criteria->condition = 'u_identity=:identity AND u_provider=:provider';
        $criteria->params = array(
            ':identity'=>$loginzaModel->identity
            , ':provider'=>$loginzaModel->provider
        );
		$user = User::model()->find($criteria);
		if (null !== $user) {
			//используем существующего пользователя
			$this->id = $user->u_id;
			$this->name = (null != $user->u_full_name) ? $user->u_full_name : $user->u_identity;
		}
		else {
			//создаем нового
			$user = new User();
			$user->u_identity = $loginzaModel->identity;
			$user->u_provider = $loginzaModel->provider;
			$user->u_email = $loginzaModel->email;
			$user->u_full_name = $loginzaModel->full_name;
			$user->save();
			$this->id = $user->u_id;
			$this->name = (null != $user->u_full_name) ? $user->u_full_name : $user->u_identity;
		}
		$this->isAuthenticated = true;
		return true;
	}

	public function getId() {
		return $this->id;
	}

	public function getIsAuthenticated() {
		return $this->isAuthenticated;
	}

	public function getName() {
		return $this->name;
	}

	public function getPersistentStates() {
		return $this->states;
	}
}

Основную часть работы выполняет метод authenticate. Рассмотрим его подробнее.

Прежде всего, мы проверяем, есть ли у нас необходимые данные для поиска пользователя или создания нового аккаунта. Это атрибуты identity и provider модели.

Затем выполняем поиск пользователя в БД. Модель User у нас создана, поэтому поиск можно выполнить с помощью метода find.
User::model()->find($criteria)
Здесь $criteria – экземпляр CDbCriteria в котором мы установили условие 'u_identity=:identity AND u_provider=:provider'.

Если пользователь найден, устанавливаем значения атрибутов name, id и isAuthenticated. Если нет — создаем нового.

Остальные методы необходимо реализовать, т.к. они объявлены в интерфейсе IUserIdentity. Они возвращают основные данные о текущем пользователе.

Благодаря им обеспечивается совместная работа с классом CWebUser. Например, будут правильно установлены атрибуты
Yii::app()->user->isGuest, Yii::app()->user->name и т.п.

Шаг 6. Обеспечиваем возврат пользователя на исходную страницу.

Т.к. в процессе аутентификации выполняется несколько редиректов, а первый этап выполняется с помощью JS кода, то нам нужно заранее сохранить адрес страницы, на которой находился пользователь. Сделать это проще всего с помощью сессий.

К тому же, есть довольно удобный компонент под названием setReturnUrl.

Он устанавливается как фильтр

public function filters() {
	return array(
		array(
			'ESetReturnUrlFilter - login, loginzalogin, logout',
		),
	);
}

Здесь мы указываем, что этот фильтр не должен применяться к методам login, loginzalogin, logout, т.к. мы должны вернуть пользователя на страницу, на которой он находился до того, как они были вызваны.

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

Source

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

Но, в любом случае, я будут рад ответить на вопросы и обсудить замечания и предложения!

До встречи!

Интересно почитать

Четыре способа увеличения продаж на конкурентном б2б-рынке

  • Аноним

    Как раз во время, спасибо!

  • Просто супер! Владимир, Вам человеческое спасибо =) !

    • Всегда пожалуйста 🙂

      Если я ничего не путаю, то именно Вы подали идею 🙂

  • Просто супер! Владимир, Вам человеческое спасибо =) !

  • BuCeFaL

    У одного пользователя могут быть аккаунты на разных провайдерах. Насколько я понимю, для этого надо создать дополнительную таблицу
    u_id | u_provider
    и authenticate() дописать «поиск пользователя» ?

    • Мы не сможем определить какие аккаунты каким пользователям принадлежат (без их помощи, конечно, но для этого придется создавать специальный интерфейс).
      Loginza такую информацию не передает, да и получить ее не может.

  • Вовка

    А как все это связать с единой учетной записью пользователя?
    ИМХО создавать учетную запись, при первой аутентификации не стоит.
    В любом случае нужно сначала создавать учетную запись, входить под ней и затем уже указывать данные для аутентификации на различных сервисах.
    Иначе смысл пропадает.

    • Боюсь, что в таком случае вообще пропадает смысл использовать
      аутентификацию через сторонние сервисы. Ведь основное их назначение —
      убрать процедуру регистрации (не вынуждать пользователя придумывать
      логин и пароль, заполнять форму, выполнять активацию через email, и, в
      то же время, получить возможность отличать одного пользователя от
      другого).

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

      P.S. Посмотрите как реализована система на http://stackoverflow.com/

      • okosoft

        Мы прикручиваем систему на http://www.moskva.me и столкнулись со следующей проблемой — в Twitter в поле photo отдает неправильную ссылку — возвращается не изображение а bad authentification

        • Точно причину не знаю. Скорее всего, у приложения логинзы не хватает прав для получения полной информации профиля.

          Приложение сможет:
          Читать твиты из вашей ленты.
          Видеть, кого вы читаете.

  • Anton

    Спасибо. На днях собираюсь попробовать реализовать авторизацию (с созданием аккаунта на первом входе) через open-api vkontakte и api mail.ru.
    Хоть вижу отчего отталкиваться.
    В моем случае через логинзу делать не вариант: 1) лишнее звено в цепи, 2) хочу получать фото юзера и грязно пиариться у его друзей.

    • С api vkontakte вообще проблем быть не должно. У них в документации есть неплохой рабочий пример. С api mail.ru не игрался.

      • Anton

        У меня проблемы не с API, а с тем, как это грамотно вписать в структуру Yii 🙂

        • Надеюсь этот пост хоть немного помог 🙂
          Для Yii без разницы используете вы сервис напрямую или через Loginza.

        • Anton

          Пост помог да 🙂
          Мне нужно напрямую.
          API используется не только для входа и упрощенной регистрации, но и для того, чтобы при создании нового акка — автоматически заполнять имя и аватар, а так же чтобы постить в новостную ленту в моем мире (и возможно вконтакте, если осилю там эту возможность)

  • Pingback: Отзывы клиентов()

  • А вот у меня несколько вопросов возникло:
    1) Если юзер авторизовался через loginza можно ли его автоматом передать в комменты disqus?

    2) Есть форум punBB он не поддерживает openID, соответственно я должен переписать механизм авторизации чтоб подключить loginza?

    • 1) Думаю, нет. На 100% не уверен, т.к. api disqus не смотрел. Но, если он использует аналогичный loginza протокол, то без подтверждения пользователя он данные получить не сможет.

      2) Да. Возможно переписывать не придется, если форум имеет api для создания плагинов. Т.е. можно будет сделать альтернативный вариант аутентификации.

  • Дима

    Хорошая статья. После прочтения в голове второй день кто-то спрашивает: ”добавлять или не добавлять на website yopen ID” 🙂

    Что делать с таблицей? Создавать отдельно таблицы для пользователей зарегестрированных стандартным способом и по опенАЙди или одну для всех?

    И еще что думаешь насчет jQuery OpenID Plug-in ?

    • Дима

      jQuery OpenID Plug-in фигня. Думал там все дела.

      • Не думаю, что работать с двумя таблицами будет удобно. Например, если вы захотите просто вывести список пользователей, то придется делать два запроса.

        Лучше добавить в таблицу пользователей поле в котором сохранить метод аутентификации.

  • Dima

    А вот это расширение ты смотрел http://www.yiiframework.com/extension/copenid ? Если оно пригодно к употреблению, было бы круто рассмотреть его на примере объединенной обычной и опенди регистрации.
    Владимир логинзу эксплуатируешь в своих проектах? Если да, то как полет?

    • Нет, этим расширением не пользовался. Спасибо за ссылку.

      В любом случае это только OpenId аутентификация, Loginza позволяет использовать и OAuth, а им сейчас пользуются активнее. Точнее посетителей с аккаунтами в социальных сетях больше чем с OpenId.

      • Дима

        О! Yo! про соцсети не думал. так это круто! я думал они все опенайди. спасибо за ответы. буду крутить логинзу, хотя как то хотелось свой мопед. Но зато с логинзой не надо следить за всеми этими шифрованными гуглами яхами и т.д. и т.п.

        • Забыл написать. В «боевых» условиях логинзу я не проверял. Ещё не
          решил что делать с недостающими данными. Они зависят от сервиса,
          который используется, а также от того, насколько подробно пользователь
          заполнил свой профиль.

        • Дима

          Понравилось возможность подключения к форуму phpbb и еще планируют коменты http://forum.loginza.ru/viewtopic.php?f=3&t=99 Но вот и минус использования подобнх сервисов, у них возникли проблемы с яху и блогером. И все! приехали, пользователи гудбай. И конретного ответа нету http://forum.loginza.ru/viewtopic.php?f=3&t=108. Вот такие моменты огорчают. А что хотели? бесплатно и никто никому ничего не должен. Хотя так надрывается доверие. И бабах лень вместе с временем зашли и сказали: давай, подключай логинзузу и все тут 🙂

  • Дима

    Как указать опционально необходимые сведения (email, fullname) ? Разбирался с http://www.yiiframework.com/extension/copenid и мучал yandex Но вот сутки пишет Сервис временно недоступен. Это он меня в баню отправил ? С этим расширением (copenid) странно работает яндекс. Если
    опционально необходимые сведения не запрашивать то проверка проходит если запрашивать то нет.(я имею ввиду ответ is_valid)

  • Доброй ночи.
    А нету ли у вас мыслей по поводу не frontend модуля для авторизации, например, в случае использования Yii как бэкэнда к приложению для соцсети. Может есть уже готовые компоненты для API различных социалок?

    • Поясните, пожалуйста, что означает «не frontend»?

      • Не верно выразился. Хотел сказать «не визуальный». Модуль который бы реализовывал API соцсетей и в том числе аунтификачию через соц сети. По факту что -то вроде http://habrahabr.ru/blogs/symfony/96543/

        • Теперь понятно. Дело в том, что такие модули придется реализовывать под каждую соц. сеть отдельно, а это приличный кусок работы.

          Готовые компоненты есть. В принципе, API социальных сетей можно считать такими компонентами.

  • He

    Если кому-то еще интересно, я недавно реализовал нечто подобное, правда пришлось, немного перепилить (видмо, создатели логинзы изменили формат данных, или я не знаю что) потому что настройка поддерживаемых сервисов не работала так, как тут написано.
    я переделал только вид loginzaWidget.php
    вот так:
    $url = $token_url.Yii::app()->createAbsoluteUrl($return_url).'&providers_set='.implode(',',$providers_set);

    и адрес виджета поменялся, теперь работает побыстрее

    'widget_url'=>'http://s1.loginza.ru/js/widget.js',

    • спасибо большое, а я то думаю почему виджет инициализируется не так как нало )

  • Pasechnikbs

    Мне кажется более логичным наследовать LoginzaModel от CFormModel а не от CModel. Ну и при таком раскладе назвать LoginzaFormModel.

    • А какие методы из CFormModel, которых нет в CModel, вы хотите использовать?

      • Pasecnikbs

        Никакие. Просто CFormModel предназначена для работы с данными которые потом теряются, а CModel с теми что сохраняются.

        • Концептуально правильно.
          Но на практике разницы не будет 🙂

        • Pasechnikbs

          Ну да. Оба варианта будут работать. Просто в Вашем подгрузятся настройки с работой базой данных и дополнительные классы. Хотя сложно представить ситуацию где они не будут подгружаться в сайте но будет использоваться LoginzaModel.

        • Фишка в том, что CFormModel наследуется от абстрактного класа CModel, поэтому правильней наследоваться от CModel. По всей видимости Вы спутали CModel с CActiveRecord.

  • Алексей Найденко

    Спасибо, очень кстати.

  • Спасибо. Сэкономили много времени 

  • Dinar Gumarov

    Как будет работать механизм авторизации при allowAutoLogin=true? Сейчас как раз занимаюсь этим вопросом. Хотелось бы пообщаться с людьми, которые знают. Мне не хватает опыта.

    • Я не совсем понимаю как вы хотите использовать allowAutoLogin вместе с Loginza. allowAutoLogin позволяет автоматически заполнить форму входа, но при аутентификации с помощью внешних ресурсов заполнять нужно форму входа на соответствующий ресурс — этот вариант не пройдет.

  • Логинза может не передать email и full_name. Email не передается при авторизации через twitter например

    • Это правда. Наиболее простое решение этой проблемы — выбирать из полученных данных наиболее подходящие. А если, например, email нужен обязательно — предлагать посетителю заполнить отдельную форму.

  • gorelovserj

    Уважаемый автор, огромное спасибо за статью и ваш блог!

    Помогите разобраться. Для чего используется state? Зачем он в базе? почему в базе он Tinyint? На форуме по Yii я уже начал дискуссию на эту тему: http://yiiframework.ru/forum/viewtopic.php?f=3&t=8794&p=52118#p52118 если интересно присоединяйтесь.
    Заранее спасибо. Если вам не сложно, пришлите ответ также на почту gorelov.serj@gmail.com, буду благодарен.

    • Поле u_state к логинзе как таковой отношения не имеет. Оно было зарезервировано для того, чтобы хранить статусы пользователя. Например, «активный», «заблокированный», «не подтвержден email» и т.п. Статусов не много и хранятся они в виде кодов, поэтому используется TINYINT.
      Из статьи этот код я просто забыл убрать.

  • cpentyc

    Что за IUserIdentity?

    • Это интерфейс в котором объявлены 5 методов, необходимые для аутентификации пользователя.

      В классе, который реализует этот интерфейс, должен содержать все эти методы. В данном случае это LoginzaUserIdentity.

  • cpentyc

    У меня была авторизация обычная
    class UserIdentity extends CUserIdentity
    {
    private $_id;
    const ERROR_ACTIVATION_INVALID=3;
    public function authenticate()
    {
    $user=User::model()->find('LOWER(username)=?',array(strtolower($this->username)));
    if($user===null)
    $this->errorCode=self::ERROR_USERNAME_INVALID;
    else if(!$user->validatePassword($this->password))
    $this->errorCode=self::ERROR_PASSWORD_INVALID;
    else if($user->isGood==0)
    $this->errorCode=self::ERROR_ACTIVATION_INVALID;
    else
    {
    $this->_id=$user->id;
    $this->setState('id_company', $user->id_company);
    $this->setState('invait', $user->id_invait);
    $this->setState('roles', $user->role);
    $this->username=$user->username;
    $this->errorCode=self::ERROR_NONE;
    }
    return $this->errorCode;
    }
    public function getId()
    {
    return $this->_id;
    }
    }

    Теперь не могу понять что делать((

    Выдает ошибку.
    Не определено свойство «WebUser.id_company».

    Не подскажите что делать.Пробовал добавить

    public $id_company = 0; не помогло

    • А куда именно вы добавили public $id_company = 0 ?

      Она должна быть добавлена в модель (класс User)

  • Я люблю этот пост, также пытается настроить его.

  • Попробуйте изменить $loginzaAuthUrl на https://loginza.ru/api/authinfo?token=