Авторизация через Соц. сеть

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Авторизация через Соц. сеть

Сообщение Shotty »

Добрый день, ребята.
Не судите строга, я ещё новичек.
Вообщем, установил я расширение от разработчиков yii - https://github.com/yiisoft/yii2-authclient

Всё сделал как в доках. Всё нормально.
Вот код файла AuthHandler

Код: Выделить всё

<?php
namespace app\components;

use app\models\Auth;
use app\models\User;
use Yii;
use yii\authclient\ClientInterface;
use yii\helpers\ArrayHelper;

/**
 * AuthHandler handles successful authentication via Yii auth component
 */
class AuthHandler
{
    /**
     * @var ClientInterface
     */
    private $client;

    public function __construct(ClientInterface $client)
    {
        $this->client = $client;
    }

    public function handle()
    {
        $attributes = $this->client->getUserAttributes();
        $email = ArrayHelper::getValue($attributes, 'email');
        $id = ArrayHelper::getValue($attributes, 'id');
        $nickname = ArrayHelper::getValue($attributes, 'login');

        /* @var Auth $auth */
        $auth = Auth::find()->where([
            'source' => $this->client->getId(),
            'source_id' => $id,
        ])->one();

        if (Yii::$app->user->isGuest) {
            if ($auth) { // login
                /* @var User $user */
                $user = $auth->user;
                $this->updateUserInfo($user);
                Yii::$app->user->login($user, Yii::$app->params['user.rememberMeDuration']);
            } else { // signup
                if ($email !== null && User::find()->where(['email' => $email])->exists()) {
                    Yii::$app->getSession()->setFlash('error', [
                        Yii::t('app', "User with the same email as in {client} account already exists but isn't linked to it. Login using email first to link it.", ['client' => $this->client->getTitle()]),
                    ]);
                } else {
                    $password = Yii::$app->security->generateRandomString(6);
                    $user = new User([
                        'username' => $nickname,
                        'github' => $nickname,
                        'email' => $email,
                        'password' => $password,
                    ]);
                    $user->generateAuthKey();
                    $user->generatePasswordResetToken();

                    $transaction = User::getDb()->beginTransaction();

                    if ($user->save()) {
                        $auth = new Auth([
                            'user_id' => $user->id,
                            'source' => $this->client->getId(),
                            'source_id' => (string)$id,
                        ]);
                        if ($auth->save()) {
                            $transaction->commit();
                            Yii::$app->user->login($user, Yii::$app->params['user.rememberMeDuration']);
                        } else {
                            Yii::$app->getSession()->setFlash('error', [
                                Yii::t('app', 'Unable to save {client} account: {errors}', [
                                    'client' => $this->client->getTitle(),
                                    'errors' => json_encode($auth->getErrors()),
                                ]),
                            ]);
                        }
                    } else {
                        Yii::$app->getSession()->setFlash('error', [
                            Yii::t('app', 'Unable to save user: {errors}', [
                                'client' => $this->client->getTitle(),
                                'errors' => json_encode($user->getErrors()),
                            ]),
                        ]);
                    }
                }
            }
        } else { // user already logged in
            if (!$auth) { // add auth provider
                $auth = new Auth([
                    'user_id' => Yii::$app->user->id,
                    'source' => $this->client->getId(),
                    'source_id' => (string)$attributes['id'],
                ]);
                if ($auth->save()) {
                    /** @var User $user */
                    $user = $auth->user;
                    $this->updateUserInfo($user);
                    Yii::$app->getSession()->setFlash('success', [
                        Yii::t('app', 'Linked {client} account.', [
                            'client' => $this->client->getTitle()
                        ]),
                    ]);
                } else {
                    Yii::$app->getSession()->setFlash('error', [
                        Yii::t('app', 'Unable to link {client} account: {errors}', [
                            'client' => $this->client->getTitle(),
                            'errors' => json_encode($auth->getErrors()),
                        ]),
                    ]);
                }
            } else { // there's existing auth
                Yii::$app->getSession()->setFlash('error', [
                    Yii::t('app',
                        'Unable to link {client} account. There is another user using it.',
                        ['client' => $this->client->getTitle()]),
                ]);
            }
        }
    }

    /**
     * @param User $user
     */
    private function updateUserInfo(User $user)
    {
        $attributes = $this->client->getUserAttributes();
        $github = ArrayHelper::getValue($attributes, 'login');
        if ($user->github === null && $github) {
            $user->github = $github;
            $user->save();
        }
    }
}
Теперь главной вопрос, или даже просьба. Кто нибудь, может кинуть пример кода авторизации через ВК? В конфиге id и секретный код приложения я записал, я знаю, что в yii2 user есть уже готовое решение, но я хочу посмотреть и понять как это реализовать без сторонних расширений, вообщем самому. Пожалуйста, кто реализовал и кому не сложно киньте кодик в пример. Всем добра)). Спасибо))
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Авторизация через Соц. сеть

Сообщение ElisDN »

Это всё oAuth2. Так и делают в ВК.
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Re: Авторизация через Соц. сеть

Сообщение Shotty »

ElisDN писал(а): 2019.03.07, 08:43 Это всё oAuth2. Так и делают в ВК.
Понял, спасибо. А есть готовое решение? Я хочу посмотреть как это уже в готовом виде делается и разбираться в коде, если не сложно конечно))
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Авторизация через Соц. сеть

Сообщение ElisDN »

Готовое решение - сами исходники yii2-authclient.
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Re: Авторизация через Соц. сеть

Сообщение Shotty »

ElisDN писал(а): 2019.03.07, 14:39 Готовое решение - сами исходники yii2-authclient.
хорошо, а как сделать через yii2-authclient, когда юзер регается, его нужно кинуть на форму, для ввода мыло и после ввода уже регистрация. и если можно тыкни в каком месте это нужно релизовать в AuthHandler.php, я новичек, помоги пожалуйста
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Авторизация через Соц. сеть

Сообщение ElisDN »

Например, прямо здесь в handle() вместо всего этого кода для гостя просто записать 'source' и 'source_id' в сессию и средиректить на страницу регистрации. А там уже делать save() вместе с email.
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Авторизация через Соц. сеть

Сообщение ElisDN »

Код: Выделить всё

Yii::$app->session->set('auth', [
    'source' => $this->client->getId(),
    'source_id' => (string)$attributes['id'],
])
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Re: Авторизация через Соц. сеть

Сообщение Shotty »

ElisDN писал(а): 2019.03.07, 14:51 Например, прямо здесь в handle() вместо всего этого кода для гостя просто записать 'source' и 'source_id' в сессию и средиректить на страницу регистрации. А там уже делать save() вместе с email.
можно пример пожалуйста, не злись если злю :D
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Re: Авторизация через Соц. сеть

Сообщение Shotty »

ElisDN писал(а): 2019.03.07, 14:54

Код: Выделить всё

Yii::$app->session->set('auth', [
    'source' => $this->client->getId(),
    'source_id' => (string)$attributes['id'],
])
https://imgur.com/vyouz1P

не выходит, можешь скинуть файлы с такой реализацией, пожалуйста, очень выручишь
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Авторизация через Соц. сеть

Сообщение ElisDN »

Yii::$app->controller->redirect(...)
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Re: Авторизация через Соц. сеть

Сообщение Shotty »

ElisDN писал(а): 2019.03.07, 15:27 Yii::$app->controller->redirect(...)
а после того как я перекинул, сохранить email из формы изи, а как ещё добавить данные из клиента, это уже другой екшин, как их получить туда?
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Re: Авторизация через Соц. сеть

Сообщение Shotty »

ElisDN писал(а): 2019.03.07, 15:27 Yii::$app->controller->redirect(...)
в сессию тоже закинуть данные от клиента?

Код: Выделить всё

Yii::$app->session->set('user', ['id' => $id,])
и после ввода мыло сохранить из сессии в БД?
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Re: Авторизация через Соц. сеть

Сообщение Shotty »

ElisDN писал(а): 2019.03.07, 15:27 Yii::$app->controller->redirect(...)
Вот, я что-то намудрил, что скажешь?

Код: Выделить всё

public function handle()
    {
        $attributes = $this->client->getUserAttributes();
        $id = ArrayHelper::getValue($attributes, 'id');

        /* Модель Auth */  
        $auth = Auth::find()->where([
            'source' => $this->client->getId(),
        ])->one();

        /* Модель User */  
        $user = User::find()->where([
            'id' => $id,
        ])->one();

        /* Если юзер гость */ 
        if (Yii::$app->user->isGuest) {

        	/* Если юзер регистрировался, тогда авторизация */
            if ($auth && $user) {

            	/* Авторизация юзера на месяц */
            	\Yii::$app->user->login($user, 3600*60*24*30);

             /* Если юзер не регался, тогда регистрация */
            } else {

            	/* Данные Auth юзера в сессию */
        	    Yii::$app->session->set('auth', ['source' => $this->client->getId()]);

        	    /* Данные User юзера в сессию */
	        	Yii::$app->session->set('user', ['data' => $attributes]);

	        	/* Редирект юзера на страницу для заполнения email */
	        	Yii::$app->controller->redirect('/test');
        }
      }
    }
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Re: Авторизация через Соц. сеть

Сообщение Shotty »

ElisDN писал(а): 2019.03.07, 15:27 Yii::$app->controller->redirect(...)
Изображение

вот сохранение в бд что скажешь
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Авторизация через Соц. сеть

Сообщение ElisDN »

Карттнки не видно.
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Re: Авторизация через Соц. сеть

Сообщение Shotty »

ElisDN писал(а): 2019.03.07, 22:05 Карттнки не видно.
Вот сохранение в БД, но мне кажется какой-то говнокод получился, но не знаю как изменить иначе, не подскажешь?

Код: Выделить всё

/* Регистрация через ВК */ 
    public function registerSocial()
    {
        /* Модель юзера */
        $user = new \app\models\User();
        $user->login = Html::encode($_SESSION['data']['user']['id']);
        $user->email = Html::encode($this->email);
        $user->password = Html::encode('false');
        $user->ip = Html::encode(\Yii::$app->request->userIP);
        $user->date = Html::encode(date('Y-m-d H:i:s'));
        $user->save();

        /* Модель соц.сети */
        $social = new \app\models\Social();
        $social->user_id = $user->id;
        $social->provider = Html::encode($_SESSION['data']['provider']);
        $social->save();

        /* Модель профиля юзера */
        $profile = new \app\models\Profile();
        $profile->user_id = $user->id;
        $profile->name = Html::encode($_SESSION['data']['user']['first_name']);
        $profile->surname = Html::encode($_SESSION['data']['user']['last_name']);
        $profile->sex = Html::encode($_SESSION['data']['user']['sex']);
        $profile->save();

        return true;
    }
kawabanga
Сообщения: 806
Зарегистрирован: 2013.10.12, 23:35
Откуда: Новосибирск

Re: Авторизация через Соц. сеть

Сообщение kawabanga »

Может лучше сначала книжки читать, чем писать ооочень слабый код и даже не знать что в нем исправить?

1) метод статический
2) метод ничего не возвращает. а если вы не зарегистрировали пользователя, или со сеть не сохранилась?
3) $user->date = Html::encode(date('Y-m-d H:i:s')); - это что за покемон? вы делаете encode на свои данные, которые по дефолту будут в заданном формате?
4) Html::encode('false'), Html::encode($_SESSION['data']['user']['id']); - использование не стандартных конструкторов языка.
5) Как минимум блок из трех сохранений обернуть в транзакцию.
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Re: Авторизация через Соц. сеть

Сообщение Shotty »

kawabanga писал(а): 2019.03.08, 17:56 Может лучше сначала книжки читать, чем писать ооочень слабый код и даже не знать что в нем исправить?

1) метод статический
2) метод ничего не возвращает. а если вы не зарегистрировали пользователя, или со сеть не сохранилась?
3) $user->date = Html::encode(date('Y-m-d H:i:s')); - это что за покемон? вы делаете encode на свои данные, которые по дефолту будут в заданном формате?
4) Html::encode('false'), Html::encode($_SESSION['data']['user']['id']); - использование не стандартных конструкторов языка.
5) Как минимум блок из трех сохранений обернуть в транзакцию.
можно пример, как нужно сделать в этом случае правильно, извини, я только учусь...
Shotty
Сообщения: 36
Зарегистрирован: 2019.03.02, 19:30

Re: Авторизация через Соц. сеть

Сообщение Shotty »

Так, а если пользователь введёт sql inj или xss? нужно же данные защищать которые были введены в форму
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Авторизация через Соц. сеть

Сообщение ElisDN »

Данные от XSS нужно энкодировать при выводе в представлениях, а не при вставке. А ActiveRecord защищает от SQL Inj.
Ответить