Статьи помеченные oauth2
Рефакторинг кода авторизации
Использование аккаунта социальной сети для авторизации
Авторизация с помощью социальной сети не должна зависеть от типа аккаунта. В предыдущем посте используется код, где в конструкторе классa common/components/SocialContact.php
выполняется оператор switch
. При добавлении обработчика для новой социальной сети, придется дописывать код, при этом меняя класс.
Перепишем конструктор так, чтобы класс не нужно было менять и он не зависел от типов социальных сетей.
Как подключить авторизацию через аккаунт
OAuth2 авторизация с использованием аккаунта
Допустим, что вы уже зарегистрированы в известной социальной сети. То есть вы уже сообщили о себе, все, что считали нужным. Очевидно вам не хочется проходить процедуру еще раз на другом ресурсе.
Авторизация с помощью социальной сети позволяет избежать повторного заполнения формы регистрации. При этом защищенность вашего аккаунта в социальной сети никак не страдает. Вы просто подтверждаете, что вы это вы. Как подключить эту услугу к проекту используя расширение yiisoft/yii2-authclient?
Как работает аутентификация OAuth2
OAuth2 аутентификация на примере Google
Если у вас есть аккаунт в Google, то вы наверняка пользовались документами. Например, электронными таблицами.
Доступ к таблицам разрешен только вам и тем, кому вы предоставите такое право. Причем доступ возможен не только из Google.
Можно просматривать список таблиц и редактировать выбранную таблицу оставаясь в рамках своего приложения. Примерно так - http://sample.vorst.ru/googl
Поиск
Метки
- 1. Как подключить авторизацию через аккаунт
- 2. Рефакторинг кода авторизации
Авторизация с помощью социальной сети не должна зависеть от типа аккаунта. В предыдущем посте используется код, где в конструкторе классa common/components/SocialContact.php
выполняется оператор switch
. При добавлении обработчика для новой социальной сети, придется дописывать код, при этом меняя класс.
Перепишем конструктор так, чтобы класс не нужно было менять и он не зависел от типов социальных сетей.
Convertor
После запроса социальной сети программа получает объект $client
. Метод getId()
объекта возвращает строку "yandex", "vkontakte" и прочее. Можно использовать эту строку в качестве имени класса, который и будет выполнять необходимый код. Классы можно хранить в подкаталоге, например common/components/convertor/Yandex.php
.
public function __construct($client, $config = []) { $client_id = $client->getId(); $attributes = $client->getUserAttributes(); $this->id = (string)$attributes['id']; // convert from individual to a single view of attributes $class_name = 'common\\components\\convertor\\' . ucfirst($client_id); $convertor = new $class_name(); $convertor->set($this, $attributes); // if email not setted then make it if (!$this->email) $this->email = "{$attributes['id']}@{$client_id}.net"; parent::__construct($config); }
Собственно сам конвертор, например common/components/convertor/Yandex.php
должен реализовать метод set
.
namespace commmon\components\convertor; class Yandex implements Convertor { public function set($obj, $attributes) { $obj->name = $attributes['first_name'] . ' ' . $attributes['last_name']; $obj->email = isset($attributes['default_email']) ? $attributes['default_email'] : false; } }
SocialLink
При первом входе с помощью аккаунта социальной сети добавляется запись в модель User
. Добавленная запись связывается с социальной сетью. Для этого создается запись в модели SocialLink
.
Если же пользователь уже вошел с помощью имени и пароля, а потом нажал еще и на кнопку социальной сети, то можно связать существующую запись в модели User
, добавив запись в модель SocialLink
.
Таким образом действие выполняется два раза, поэтому стоит выделить его в отдельный метод. Полный текст common/components/SocialContact.php
теперь следующий.
namespace common\components; use Yii; use yii\base\BaseObject; use yii\base\InvalidValueException; use common\models\SocialLink; use common\models\User; class SocialContact extends BaseObject { public $id; public $name; public $email; private $_link; public function __construct($client, $config = []) { $client_id = $client->getId(); $attributes = $client->getUserAttributes(); $this->id = (string)$attributes['id']; // convert from individual to a single view of attributes $class_name = 'common\\components\\convertor\\' . ucfirst($client_id); $convertor = new $class_name(); $convertor->set($this, $attributes); // if email not setted then make it if (!$this->email) $this->email = "{$attributes['id']}@{$client_id}.net"; parent::__construct($config); } public function registration($client_id) { if (User::find()->where(['email' => $this->email])->exists()) { Yii::$app->getSession()->setFlash('error', [ Yii::t('app', 'User with {email} have been exist, but not linked to {client}. ' . 'Try to login with other social network or with name and password.', [ 'email' => $this->email, 'client' => $client_id, ]), ]); } else { if(User::find()->where(['name' => $this->name])->exists()) { Yii::$app->getSession()->setFlash('error', [ Yii::t('app', 'A user named {name} already exists. ' . 'Try logging in if you have registered before.', [ 'name' => $this->name, ]), ]); } else { $password = Yii::$app->security->generateRandomString(6); $user = new User([ 'name' => $this->name, 'email' => $this->email, 'password' => $password, 'status' => User::STATUS_ACTIVE, ]); $user->generateAuthKey(); $user->generatePasswordResetToken(); $transaction = $user->getDb()->beginTransaction(); if ($user->save()) { if ($this->makeLink($client_id, $user->id)) { $transaction->commit(); Yii::$app->user->login($user); } else { throw new InvalidValueException($this->showErrors($this->_link)); } } else { throw new InvalidValueException($this->showErrors($user)); } } } } public function makeLink($client_id, $user_id) { $this->_link = new SocialLink([ 'user_id' => $user_id, 'source' => $client_id, 'source_id' => $this->id, ]); return $this->_link->save(); } private function showErrors($model) { $out = 'Can\'t save ' . $model->tableName() . "\n"; foreach($model->getErrors() as $field => $messages) { $out .= "«{$field}»\n"; foreach($messages as $message) { $out .= "{$message}\n"; } $out .= "\n"; } return $out; } }
Теперь действие авторизации в контроллере frontend/controllers/SiteController.php
стало проще и понятнее, а значит мы достигли цели :).
public function onAuthSuccess($client) { $social_contact = new SocialContact($client); $social_link = SocialLink::find()->where([ 'source' => $client->getId(), 'source_id' => $social_contact->id, ])->one(); if (Yii::$app->user->isGuest) { if ($social_link) { // authorization Yii::$app->user->login($social_link->user); } else { // registration $social_contact->registration($client->getId()); } } else { // the user is already registered if (!$social_link) { // add external service of authentification $social_contact->makeLink($client->getId(), Yii::$app->user->id); } } }
Заключение
Полная версия с аватаром в расширении sergmoro1/yii2-user.
Оставьте комментарий
Только зарегистрированные пользователи могут оставлять комментарии. Пожалуйста войдите или пройдите регистрацию.
Можно авторизоваться, используя социальную сеть-
-
-