Содержание

Yii2 basic авторизация через БД во всплывающем (модальном) окне

Шаг 1

Для реализации авторизации Yii2 basic во всплывающем окне я возьму ранее написанный пример с авторизацией из БД: Yii2 basic, авторизация и регистрация через БД. Для этого клонируем его и подготавливаем:

mkdir yii2-auth-in-modal.local
cd yii2-auth-in-modal.local
git clone https://github.com/egor/yii2-basic-auth-through-db.git .
composer update

Настраиваем соединение с БД и запускаем миграцию:

yii migrate

Шаг 2

Создаем каталог для хранения виджтов app/widgets и каталог для представлений (view) виджетов app/widgets/views.

Создаем виджет LoginFormWidget для отображения модального окна с формой авторизации, app/widgets/LoginFormWidget.php:

<?php

namespace app\widgets;

use Yii;
use yii\base\Widget;
use app\models\LoginForm;

class LoginFormWidget extends Widget {

    public function run() {
        if (Yii::$app->user->isGuest) {
            $model = new LoginForm();
            return $this->render('loginFormWidget', [
                'model' => $model,
            ]);
        } else {
            return ;
        }
    }

}

В представление (view) виджета LoginFormWidget добавляем модально окно с формой авторизации, app/widgets/views/loginFormWidget.php:

<?php

use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\bootstrap\Modal;

Modal::begin([
    'header'=>'<h4>Login</h4>',
    'id'=>'login-modal',
]);
?>

    <p>Please fill out the following fields to login:</p>

<?php $form = ActiveForm::begin([
    'id' => 'login-form',
    'enableAjaxValidation' => true,
    'action' => ['site/ajax-login']
]);
echo $form->field($model, 'email')->textInput();
echo $form->field($model, 'password')->passwordInput();
echo $form->field($model, 'rememberMe')->checkbox();
?>

<div>
    If you forgot your password you can <?= Html::a('reset it', ['site/request-password-reset']) ?>.
</div>
<div class="form-group">
    <div class="text-right">

        <?php
        echo Html::button('Cancel', ['class' => 'btn btn-default', 'data-dismiss' => 'modal']);
        echo Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']); 
        ?>

    </div>
</div>

<?php 
ActiveForm::end();
Modal::end();

Шаг 3

Добавляем ajax действие проверки и авторизации пользователя в контроллер Site, app/controllers/SiteController.php:

public function actionAjaxLogin() {
    if (Yii::$app->request->isAjax) {
        $model = new LoginForm();
        if ($model->load(Yii::$app->request->post())) {
            if ($model->login()) {
                return $this->goBack();
            } else {
                Yii::$app->response->format = yii\web\Response::FORMAT_JSON;
                return \yii\widgets\ActiveForm::validate($model);
            }
        }
    } else {
        throw new HttpException(404 ,'Page not found');
    }
}

Шаг 4

В главном макете app/views/layouts/main.php в блок use добавляем виджет LoginFormWidget:

use app\widgets\LoginFormWidget;

Вызов виджета LoginFormWidget, вставляем после <?php $this->beginBody() ?>:

<?= (Yii::$app->user->isGuest ? LoginFormWidget::widget([]) : ''); ?>

Заменим ссылку ведущую на страницу авторизации для вызов модального окна, с:

$menuItems[] = ['label' => 'Login', 'url' => ['/site/login']];

Меняем на:

$menuItems[] = ['label' => 'Login', 'url' => '#', 'options' => ['data-toggle' => 'modal', 'data-target' => '#login-modal']];

В итоге app/views/layouts/main.php примет вид:

<?php

/* @var $this \yii\web\View */
/* @var $content string */

use yii\helpers\Html;
use yii\bootstrap\Nav;
use yii\bootstrap\NavBar;
use yii\widgets\Breadcrumbs;
use app\assets\AppAsset;
use app\widgets\LoginFormWidget;

AppAsset::register($this);
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
    <meta charset="<?= Yii::$app->charset ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <?= Html::csrfMetaTags() ?>
    <title><?= Html::encode($this->title) ?></title>
    <?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<?php if (Yii::$app->user->isGuest) { echo LoginFormWidget::widget([]); } ?>
<div class="wrap">
    <?php
    NavBar::begin([
        'brandLabel' => 'My Company',
        'brandUrl' => Yii::$app->homeUrl,
        'options' => [
            'class' => 'navbar-inverse navbar-fixed-top',
        ],
    ]);
    $menuItems = [
        ['label' => 'Home', 'url' => ['/site/index']],
        ['label' => 'About', 'url' => ['/site/about']],
        ['label' => 'Contact', 'url' => ['/site/contact']],
    ];
    if (Yii::$app->user->isGuest) {
        $menuItems[] = ['label' => 'Signup', 'url' => ['/site/signup']];
        $menuItems[] = ['label' => 'Login', 'url' => '#', 'options' => ['data-toggle' => 'modal', 'data-target' => '#login-modal']];
    } else {
        $menuItems[] = '<li>'
            . Html::beginForm(['/site/logout'], 'post')
            . Html::submitButton(
                'Logout (' . Yii::$app->user->identity->username . ')',
                ['class' => 'btn btn-link logout']
            )
            . Html::endForm()
            . '</li>';
    }
    echo Nav::widget([
        'options' => ['class' => 'navbar-nav navbar-right'],
        'items' => $menuItems,
    ]);
    NavBar::end();
    ?>

    <div class="container">
        <?= Breadcrumbs::widget([
            'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
        ]) ?>
        <?= $content ?>
    </div>
</div>

<footer class="footer">
    <div class="container">
        <p class="pull-left">© My Company <?= date('Y') ?></p>
        <p class="pull-right"><?= Yii::powered() ?></p>
    </div>
</footer>

<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>

Сохраняем и запускаем.

Yii2 basic, авторизация из коробки во всплывающем (модальном) окне

Пример описанный выше подойдет и для авторизации имеющейся в Yii2 basic из коробки с небольшими правками.

Шаг 1

Шаг 1 из предыдущего примера пропускаем, вместо него устанавливаем yii2 basic (Как установить Yii 2 basic, краткая инструкция) или открываем существующий проект с авторизацией из коробки.

Шаг 2

Выполняем шаг 2 из предыдущего примера с некоторыми изменениями. В представлении виджета app/widgets/views/loginFormWidget.php заменяем:

echo $form->field($model, 'email')->textInput();

на:

echo $form->field($model, 'username')->textInput();

Т.к. по умолчанию логин это username. Далее убираем блок отвечающий за сброс пароля, т.к. из коробки он не реализован. Все остальное остается как есть.

В итоге app/widgets/LoginFormWidget.php примет вид:

<?php

namespace app\widgets;

use Yii;
use yii\base\Widget;
use app\models\LoginForm;

class LoginFormWidget extends Widget {

    public function run() {
        if (Yii::$app->user->isGuest) {
            $model = new LoginForm();
            return $this->render('loginFormWidget', [
                'model' => $model,
            ]);
        } else {
            return ;
        }
    }

}

Представление виджета LoginFormWidget примет вид, app/widgets/views/loginFormWidget.php:

<?php

use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\bootstrap\Modal;

Modal::begin([
    'header'=>'<h4>Login</h4>',
    'id'=>'login-modal',
]);
?>

    <p>Please fill out the following fields to login:</p>

<?php $form = ActiveForm::begin([
    'id' => 'login-form',
    'enableAjaxValidation' => true,
    'action' => ['site/ajax-login']
]);
echo $form->field($model, 'username')->textInput();
echo $form->field($model, 'password')->passwordInput();
echo $form->field($model, 'rememberMe')->checkbox();
?>

<div class="form-group">
    <div class="text-right">

        <?php
        echo Html::button('Cancel', ['class' => 'btn btn-default', 'data-dismiss' => 'modal']);
        echo Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']); 
        ?>

    </div>
</div>

<?php 
ActiveForm::end();
Modal::end();

Шаг 3

Шаг 3 из предыдущего примера выполняем полностью.

В итоге actionAjaxLogin в app/controllers/SiteController.php примет вид:

public function actionAjaxLogin() {
    if (Yii::$app->request->isAjax) {
        $model = new LoginForm();
        if ($model->load(Yii::$app->request->post())) {
            if ($model->login()) {
                return $this->goBack();
            } else {
                Yii::$app->response->format = yii\web\Response::FORMAT_JSON;
                return \yii\widgets\ActiveForm::validate($model);
            }
        }
    } else {
        throw new HttpException(404 ,'Page not found');
    }
}

Шаг 4

Шаг 4 из предыдущего примера подвергнется небольшим изменениям. А именно в главном макете app/views/layouts/main.php заменяем ссылку вызова страницы авторизации с:

['label' => 'Login', 'url' => ['/site/login']]

на:

['label' => 'Login', 'url' => '#', 'options' => ['data-toggle' => 'modal', 'data-target' => '#login-modal']]

Остальное делаем как написано. В итоге app/views/layouts/main.php примет вид:

<?php

/* @var $this \yii\web\View */
/* @var $content string */

use yii\helpers\Html;
use yii\bootstrap\Nav;
use yii\bootstrap\NavBar;
use yii\widgets\Breadcrumbs;
use app\assets\AppAsset;
use app\widgets\LoginFormWidget;

AppAsset::register($this);
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
    <meta charset="<?= Yii::$app->charset ?>">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <?= Html::csrfMetaTags() ?>
    <title><?= Html::encode($this->title) ?></title>
    <?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<?= (Yii::$app->user->isGuest ? LoginFormWidget::widget([]) : ''); ?>
<div class="wrap">
    <?php
    NavBar::begin([
        'brandLabel' => 'My Company',
        'brandUrl' => Yii::$app->homeUrl,
        'options' => [
            'class' => 'navbar-inverse navbar-fixed-top',
        ],
    ]);
    echo Nav::widget([
        'options' => ['class' => 'navbar-nav navbar-right'],
        'items' => [
            ['label' => 'Home', 'url' => ['/site/index']],
            ['label' => 'About', 'url' => ['/site/about']],
            ['label' => 'Contact', 'url' => ['/site/contact']],
            Yii::$app->user->isGuest ? (
            ['label' => 'Login', 'url' => '#', 'options' => ['data-toggle' => 'modal', 'data-target' => '#login-modal']]
            ) : (
                '<li>'
                . Html::beginForm(['/site/logout'], 'post')
                . Html::submitButton(
                    'Logout (' . Yii::$app->user->identity->username . ')',
                    ['class' => 'btn btn-link logout']
                )
                . Html::endForm()
                . '</li>'
            )
        ],
    ]);
    NavBar::end();
    ?>

    <div class="container">
        <?= Breadcrumbs::widget([
            'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
        ]) ?>
        <?= $content ?>
    </div>
</div>

<footer class="footer">
    <div class="container">
        <p class="pull-left">© My Company <?= date('Y') ?></p>
        <p class="pull-right"><?= Yii::powered() ?></p>
    </div>
</footer>

<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>

По окончанию жмем на Login, вводим логин и пароль (admin, admin).

Yii2 advanced. Авторизация во всплывающем (модальном) окне

Шаг 1

Открываем существующий проект на Yii2 advanced или устанавливаем новый (Как установить Yii 2 advanced, краткая инструкция). И используем инструкцию описанную выше с некоторыми изменениями.

Шаг 1 пропускаем из основного примера.

Шаг 2

Для шага 2 из основного примера, меняем путь к каталогу хранения виджета и его представления на frontend/widgets и frontend/widgets/views соответственно.

В классе виджета frontend/widgets/LoginFormWidget.php меняем namespace c:

namespace app\widgets;

на:

namespace frontend\widgets;

Также меняем путь к LoginForm c:

use app\models\LoginForm;

на:

use common\models\LoginForm;

В представление виджета frontend/widgets/views/loginFormWidget.php заменяем:

echo $form->field($model, 'email')->textInput();

на:

echo $form->field($model, 'username')->textInput();

Т.к. по умолчанию логин это username.

Остальное в шаге 2 из основного примера оставляем как есть.

Виджет frontend/widgets/LoginFormWidget.php примет вид:

<?php

namespace frontend\widgets;

use Yii;
use yii\base\Widget;
use common\models\LoginForm;

class LoginFormWidget extends Widget {

    public function run() {
        if (Yii::$app->user->isGuest) {
            $model = new LoginForm();
            return $this->render('loginFormWidget', [
                'model' => $model,
            ]);
        } else {
            return ;
        }
    }

}

Представление виджета LoginFormWidget примет вид, frontend/widgets/views/loginFormWidget.php:

<?php

use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use yii\bootstrap\Modal;

Modal::begin([
    'header'=>'<h4>Login</h4>',
    'id'=>'login-modal',
]);
?>

    <p>Please fill out the following fields to login:</p>

<?php $form = ActiveForm::begin([
    'id' => 'login-form',
    'enableAjaxValidation' => true,
    'action' => ['site/ajax-login'],
]);
echo $form->field($model, 'username')->textInput();
echo $form->field($model, 'password')->passwordInput();
echo $form->field($model, 'rememberMe')->checkbox();
?>

    <div>
        If you forgot your password you can <?= Html::a('reset it', ['site/request-password-reset']) ?>.
    </div>
    <div class="form-group">
        <div class="text-right">

            <?php
            echo Html::button('Cancel', ['class' => 'btn btn-default', 'data-dismiss' => 'modal']);
            echo Html::submitButton('Login', ['class' => 'btn btn-primary', 'name' => 'login-button']);
            ?>

        </div>
    </div>

<?php
ActiveForm::end();
Modal::end();

Шаг 3

Шаг 3 из основного примера делаем полностью.

В итоге actionAjaxLogin в frontend/controllers/SiteController.php примет вид:

public function actionAjaxLogin() {
    if (Yii::$app->request->isAjax) {
        $model = new LoginForm();
        if ($model->load(Yii::$app->request->post())) {
            if ($model->login()) {
                return $this->goBack();
            } else {
                Yii::$app->response->format = yii\web\Response::FORMAT_JSON;
                return \yii\widgets\ActiveForm::validate($model);
            }
        }
    } else {
        throw new HttpException(404 ,'Page not found');
    }
}

Шаг 4

Шаг 4 из основного примера имеет небольшие отличия. Открываем основной макет frontend/views/layouts/main.php, в блок use добавляем виджет с модальным окном и формой авторизации:

use frontend\widgets\LoginFormWidget;

Остальное остается как описано в шаге 4 из основного примера.

В итоге frontend/views/layouts/main.php примет вид:

<?php

/* @var $this \yii\web\View */
/* @var $content string */

use yii\helpers\Html;
use yii\bootstrap\Nav;
use yii\bootstrap\NavBar;
use yii\widgets\Breadcrumbs;
use frontend\assets\AppAsset;
use common\widgets\Alert;
use frontend\widgets\LoginFormWidget;

AppAsset::register($this);
?>
<?php $this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>
    <meta charset="<?= Yii::$app->charset ?>">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <?= Html::csrfMetaTags() ?>
    <title><?= Html::encode($this->title) ?></title>
    <?php $this->head() ?>
</head>
<body>
<?php $this->beginBody() ?>
<?= (Yii::$app->user->isGuest ? LoginFormWidget::widget([]) : ''); ?>
<div class="wrap">
    <?php
    NavBar::begin([
        'brandLabel' => 'My Company',
        'brandUrl' => Yii::$app->homeUrl,
        'options' => [
            'class' => 'navbar-inverse navbar-fixed-top',
        ],
    ]);
    $menuItems = [
        ['label' => 'Home', 'url' => ['/site/index']],
        ['label' => 'About', 'url' => ['/site/about']],
        ['label' => 'Contact', 'url' => ['/site/contact']],
    ];
    if (Yii::$app->user->isGuest) {
        $menuItems[] = ['label' => 'Signup', 'url' => ['/site/signup']];
        $menuItems[] = ['label' => 'Login', 'url' => '#', 'options' => ['data-toggle' => 'modal', 'data-target' => '#login-modal']];
    } else {
        $menuItems[] = '<li>'
            . Html::beginForm(['/site/logout'], 'post')
            . Html::submitButton(
                'Logout (' . Yii::$app->user->identity->username . ')',
                ['class' => 'btn btn-link logout']
            )
            . Html::endForm()
            . '</li>';
    }
    echo Nav::widget([
        'options' => ['class' => 'navbar-nav navbar-right'],
        'items' => $menuItems,
    ]);
    NavBar::end();
    ?>

    <div class="container">
        <?= Breadcrumbs::widget([
            'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
        ]) ?>
        <?= Alert::widget() ?>
        <?= $content ?>
    </div>
</div>

<footer class="footer">
    <div class="container">
        <p class="pull-left">© My Company <?= date('Y') ?></p>

        <p class="pull-right"><?= Yii::powered() ?></p>
    </div>
</footer>

<?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>

Добавляем нового пользователя в БД. И пробуем.