Yii2 Авторизация через социальные сети

В наше время на многих сайтах используется авторизация через соцсети и сервисы.  В этой статье собрана практически вся информация по yii2-eauth модулю.

Ссылка на гитхаб-репозиторий данного расширения. 

Не буду подробна рассписывать как устанавливать это расширение, на гитхабе это подробно изложено.

Расскажу как связать это расширение с модлеью пользователей и получать ссылки на аватарки пользователей (используется шаблон Yii advanced). 

В папке "frontend/components" создаем папку "oauth". 

Далее нам необходимо создать наследников классов сервисов авторизации. 

namespace frontend\components\oauth;

class FacebookOAuth2Service extends \nodge\eauth\services\FacebookOAuth2Service
{

}

 В своем классе мы должны переопределить метод  fetchAttributes(). Для Facebook это будет выглядить 
 

protected function fetchAttributes()
    {
        $this->attributes = $this->makeSignedRequest('me', [
            'query' => [
                'fields' => join(',', [
                    'id',
                    'name',
                    'link',
                    'email',
                    'verified',
                    'first_name',
                    'last_name',
                    'gender',
                    'birthday',
                    'hometown',
                    'location',
                    'locale',
                    'timezone',
                    'updated_time',
                ])
            ]
        ]);

        $this->attributes['avatar'] = $this->baseApiUrl.$this->getId().'/picture?width=100&height=100';

        return true;
    }

Для вконтакте 

  protected function fetchAttributes()
    {
        $tokenData = $this->getAccessTokenData();
        $info = $this->makeSignedRequest('users.get', [
            'query' => [
                'uids' => $tokenData['params']['user_id'],
                'fields' => 'nickname, sex, bdate, city, country, timezone, photo, photo_50, photo_big, photo_rec',
            ],
        ]);

        $info = $info['response'][0];

        $this->attributes = $info;
        $this->attributes['id'] = $info['uid'];
        $this->attributes['name'] = $info['first_name'] . ' ' . $info['last_name'];
        $this->attributes['url'] = 'http://vk.com/id' . $info['uid'];

        if (!empty($info['nickname'])) {
            $this->attributes['username'] = $info['nickname'];
        } else {
            $this->attributes['username'] = 'id' . $info['uid'];
        }

        $this->attributes['gender'] = $info['sex'] == 1 ? 'F' : 'M';

        if (!empty($info['timezone'])) {
            $this->attributes['timezone'] = timezone_name_from_abbr('', $info['timezone'] * 3600, date('I'));
        }
        if (!empty($info['photo_50'])) {
            $this->attributes['avatar'] =$info['photo_50'];
        }

        return true;
    }

Так ка все эти классы наследуются от  nodge\eauth\ServiceBase в котором реализован метод getAttribute(), нам нужно чтоб в каждом нашем классе наследнике задавать атрибут "avatar" , что мы и делаем.

В своих классах вы можете также реализовать получение email пользователей от тех сервисов которые это позволяют.

После того как реализовали все классы нужных нам соцсетей правим основной конфиг приложения и указываем в качестве классов сервисов свои классы 

 'google' => [     'class' => 'frontend\components\oauth\GoogleOAuth2Service',
                    'clientId' => '',
                    'clientSecret' => '',
                    'title' => 'Google',
                ],

Далее в таблицу в которой у нас хранятся пользователи (у меня она называется members) добавляем поля "service, social_id, avatar, display_name, profile" .

Правим модель пользователей 

Изменяем метод findByEAuth($service)

 public static function findByEAuth($service) {
        if (!$service->getIsAuthenticated()) {
            throw new ErrorException('EAuth user should be authenticated before creating identity.');
        }

        $model=self::getMemeberByService($service);
        $model->profile=$service->getAttributes();

        Yii::$app->getSession()->set('user-'.$model->id, $model);
        return $model;
    }

и надо реализовать метод getMemeberByService($service)

public static function getMemeberByService($service)
    {
// пытаемся найти нашего пользователя        
$model= Members::find()->where(['service'=>$service->getServiceName(),'social_id'=>$service->getId()])->one();
       if (!$model)
       {
           // если не нашли то создаем нового 
           $model=new Members();
           // создаем уникальное имя пользователя 
           $model->username=$service->getServiceName().'-'.$service->getId();
            // генерируем пароль 
           $model->password_hash=Yii::$app->security->generatePasswordHash(Yii::$app->security->generateRandomString());
           $model->auth_key=Yii::$app->security->generateRandomString();
           $model->service=$service->getServiceName();
           $model->social_id=$service->getId();
           $model->display_name=$service->getAttribute('name');

       }
        $model->avatar=$service->getAttribute('avatar','');
        $model->save();
        return $model;

    }

В этом также можно реализовать сохранение профиля полученного от соцсети.

Правим  метод  findIdentity($id)

public static function findIdentity($id)
    {
     
        if (Yii::$app->getSession()->has('user-'.$id)) {
            return Yii::$app->getSession()->get('user-'.$id);
        }
        else {
             return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
        }
    }

После этого мы можем работать с пользователями которые через соцсети как с обычными пользователями. 

 

Обсуждение