pbAuth — мощная система авторизации, регистрации и управления профилем для PageBlocks

pbAuth — это готовый пакет аутентификации для PageBlocks, построенный на контроллерах. Он позволяет быстро внедрить регистрацию, вход, восстановление пароля и управление профилем пользователя без лишней рутины. Все маршруты, формы и ответы легко кастомизируются.



Возможности:
  • Авторизация и регистрация через POST-запросы
  • Восстановление и смена пароля
  • Профиль пользователя с редактированием данных
  • Валидация и вывод ошибок через Fenom
  • Поддержка CSRF и flash-сообщений
  • Расширяемые контроллеры и шаблоны
Демо

Быстрый старт


1. Активация роутинга
Для работы pbAuth необходимо включить роутинг в PageBlocks. Убедитесь, что системная настройка pageblocks_routing установлена в значение Route Only или Full API.

2. Подключение JavaScript для форм
Если вы хотите, чтобы формы авторизации и регистрации работали без перезагрузки страницы, включите настройку pageblocks_load_scripts. Это автоматически подключит необходимые скрипты, обрабатывающие отправку форм через AJAX, а также отрисовку ошибок и сообщений.

3. Вставка чанка с авторизацией
В шапку вашего сайта рекомендуется вставить один из готовых файловых чанков:
  • auth — классическая панель с кнопками входа/регистрации и отображением профиля,
  • auth_modal — модальное окно (если вы хотите встроить формы без отдельных страниц).
Пример подключения:
{insert 'file:auth/chunks/auth.tpl'}

Код чанка auth.tpl:
{auth}
    <a href="{route 'pageProfile'}" class="d-flex align-items-center gap-2 text-dark text-decoration-none">
        <div class="avatar d-flex align-items-center justify-content-center rounded-5 bg-secondary-subtle overflow-hidden" style="width:48px;height:48px">
            <img src="{$modx->user->getGravatar()}" width="48" height="48" alt="{$modx->user->username}">
        </div>
        <div class="d-flex flex-column">
            <strong>{$modx->user->username}</strong>
            <span>{$modx->user->email}</span>
        </div>
    </a>
{/auth}

{guest}
    <ul class="navbar-nav d-flex align-items-center list-unstyled mb-0">
        <li class="nav-item">
            <a class="btn btn-sm" href="{route 'pageLogin'}">{lang 'auth.login_title'}</a>
        </li>
        <li class="nav-item">
            <a class="btn btn-light btn-sm" href="{route 'pageRegister'}">{lang 'auth.register_title'}</a>
        </li>
    </ul>
{/guest}

Объяснение новых тегов:
  • {auth} и {guest} — условные блоки, отображающие содержимое только для авторизованных или неавторизованных пользователей соответственно.
  • {route 'имя_маршрута'} — получение ссылки по имени маршрута. Удобно при рефакторинге, чтобы не менять ссылки в шаблонах вручную.
  • {lang 'ключ_лексикона'} — получение фраз из языковых файлов (например, {lang 'auth.register_title'} — ищет переменную register_title из файла App/lang/en/auth.php).

4. Маршруты и структура
pbAuth поставляется с готовым набором маршрутов, которые регистрируются в файле core/App/routes/auth.php.
// Только для неавторизованных пользователей
Route::middleware('guest')->group(function () {
    Route::get('/login', 'Auth\LoginController@show')->name('pageLogin');
    Route::post('/login', 'Auth\LoginController@login')->name('login');

    Route::get('/register', 'Auth\RegisterController@show')->name('pageRegister');
    Route::post('/register', 'Auth\RegisterController@register')->name('register');

    Route::get('/forgot-password', 'Auth\ForgotPasswordController@show')->name('pageForgotPassword');
    Route::post('/forgot-password', 'Auth\ForgotPasswordController@forgotPassword')->name('forgotPassword');

    Route::get('/reset-password/{token}', 'Auth\ResetPasswordController@show')->name('pageResetPassword');
    Route::post('/reset-password', 'Auth\ResetPasswordController@resetPassword')->name('resetPassword');
});

// Только для авторизованных
Route::middleware('auth')->group(function () {
    Route::get('/confirm-password', 'Auth\ConfirmPasswordController@show')->name('pageConfirmPassword');
    Route::post('/confirm-password', 'Auth\ConfirmPasswordController@confirmPassword')->name('confirmPassword');

    Route::get('/profile', 'Auth\ProfileController@show')->name('pageProfile');
    Route::post('/profile', 'Auth\ProfileController@updateProfile')->name('updateProfile');

    Route::get('/profile/password', 'Auth\ChangePasswordController@show')->name('pageChangePassword');
    Route::post('/profile/password', 'Auth\ChangePasswordController@changePassword')->name('changePassword');

    Route::get('/logout', 'Auth\LoginController@logout')->name('logout');
});

// Подтверждение email
Route::get('/verify-email/{token}', 'Auth\AuthController@verifyEmail')->name('verifyEmail');

Список маршрутов:
  • /login — форма входа
  • /register — регистрация
  • /forgot-password — восстановление пароля
  • /reset-password/{token} — сброс пароля
  • /confirm-password — подтверждение пароля
  • /profile — редактирование профиля
  • /profile/password — смена пароля
  • /logout — выход
  • /verify-email/{token} — подтверждение email
Если вы используете чанк auth_modal, то отдельные страницы регистрации, входа и восстановления пароля можно не выводить — они будут загружаться через модальное окно.

Структура элементов аутентификации
  • Контроллеры — /core/App/Http/Controllers/Auth/
  • Основная логика регистрации, входа, восстановления пароля и т.д.
  • Шаблоны — /core/App/elements/auth/
  • Fenom-шаблоны форм и уведомлений, которые можно кастомизировать.
  • Лексиконы (переводы) — /core/App/lang/
  • Переводы на разные языки для сообщений, ошибок и интерфейса.
  • Маршруты — /core/App/routes/auth.php
  • Определяют доступные URL и обрабатывающие их контроллеры.

Пример авторизации


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

1. Создание маршрута для авторизации
Сначала задаем маршрут /login, который будет доступен только для неавторизованных пользователей. Для этого оборачиваем его в middleware guest:
Route::middleware('guest')->get('/login', 'LoginController@show')->name('pageLogin');

2. Добавление ссылки в шаблон
Теперь можно вставить в шаблон ссылку на страницу авторизации.
<a class="btn btn-sm" href="{route 'pageLogin'}">Login</a>
Вместо жестко заданного URL мы используем имя маршрута — это очень удобно, если ссылка маршрута измениться то вам не нужно править шаблон.

3. Контроллер авторизации
Создаём контроллер LoginController, который будет отвечать за вывод формы входа:
<?php

namespace PageBlocks\App\Http\Controllers\Auth;

use Boshnik\PageBlocks\Facades\Request;

class LoginController extends AuthController
{
   public function show()
    {
        return view('file:auth/templates/auth', [
            'title' => lang('auth.login_title'),
            'form' => 'form.login'
        ]);
    }
}
Здесь мы используем метод view(), чтобы отобразить шаблон auth/templates/auth.tpl. Также передаем параметры:
  • title — заголовок страницы (будет использоваться в теге title);
  • form — название формы, которая будет подгружена внутрь шаблона.
4. Шаблон auth.tpl
<head>
    <title>{$title} | {'site_name'|config}</title>
</head>
<section class="section-auth">
    <div class="container">
        {block 'content'}
            <div class="row">
                <div class="col-12 col-md-5 mx-auto my-5">
                    {set $chunkPath = 'file:auth/chunks/' ~ $form}
                    {include $chunkPath}
                </div>
            </div>
        {/block}
    </div>
</section>

5. Обработка формы входа
Добавляем маршрут, который будет принимать POST-запрос от формы:
Route::post('/login', 'LoginController@login')->name('login');

6. Настройка формы
В HTML-форме нужно указать action с именем маршрута login, а также method=«post». Обязательно добавьте атрибут data-pbform, чтобы активировать обработку через JavaScript:
<form class="border rounded-4 p-5" action="{route 'login'}" method="post" data-pbform>

7. Обработка формы и отображение ошибок
7.1 Через JavaScript (если включена настройка pageblocks_load_scripts)
Ошибки обрабатываются без перезагрузки страницы. После каждого поля необходимо добавить блок для показа ошибки:
<span data-error="namefield"></span>

Пример с полем:
<div class="form-group mb-3">
        <label class="mb-2" for="username">{lang 'auth.field_login'}</label>
        <input type="text" name="username" id="username" class="form-control" required>
        <span class="invalid-feedback" data-error="username"></span>
    </div>

Также можно вывести сообщение об ошибке или успехе формы:
<p data-pbform-message></p>

7.2 Через flash-сообщения (если JS-обработка отключена)
Если JavaScript-обработка выключена, форма будет отправлена обычным способом, и данные вернутся через flash-сообщения. Они доступны в шаблоне в виде переменных:
  • errors — ошибки полей;
  • old_input — предыдущие значения полей;
  • success_message — сообщение об успешной операции;
  • error_message — общая ошибка.

Пример вывода сообщений:
{if $success_message}
    <p class="form-message text-center text-success" >{$success_message}</p>
{elseif $error_message}
    <p class="form-message text-center text-error text-danger">{$error_message}</p>
{/if}

Пример поля с ошибкой и предыдущим значением:
<div class="form-group mb-3">
    <label class="mb-2" for="username">{lang 'auth.field_login'}</label>
    <input type="text" name="username" id="username" class="form-control{if $errors.username} is-invalid{/if}" value="{$old_input.username}" required>
    <span class="invalid-feedback" data-error="username">{$errors.username}</span>
</div>

8. Метод login() в контроллере
В этом методе происходит вся логика авторизации:

public function login(Request $request)
{
    // Валидируем данные
    $request->validate([
        'honeypot' => 'empty',
        'username' => 'required',
        'password' => 'required|min:8'
    ]);
    
    // Мы можем авторизовать пользователя по любому полю, 
    // проверяем сначала его имя, если не нашли проверяем почту и затем телефон.
    $user = $this->modx->getObject($this->userClassKey, ['username' => $request->username]);
    if (!$user) {
        $profile = $this->modx->getObject($this->profileClassKey, ['email' => $request->username])
            ?: $this->modx->getObject($this->profileClassKey, ['phone' => $request->username]);

        if (!$profile || !$user = $profile->getOne('User')) {
            // Если ничего не нашли то возвращаем ошибку, что не нашли пользователя
            return response()->error('', [
                'username' => $this->modx->lexicon('user_err_nf'),
            ]);
        }

        $request->username = $user->username;
    }
   
    // Авторизовываем пользователя через процессор 
    $response = $this->modx->runProcessor('Security/Login', [
        'username' => $request->username,
        'password' => $request->password,
        'rememberme' => $request->remember ?? false,
        'login_context' => $this->modx->context->key ?? 'web',
        'add_contexts' => 'en,de' // добавляем доп. контексты для авторизации
    ]);

    if ($response->isError()) {
        return response()->error($response->getMessage());
    }
     
    // Если все хорошо, то перекидываем на главную страницу
    return response()->success('', '/');
}

В контроллере рекомендуется использоваться методы error и success класса Response. Эти методы автоматически определяют, был ли запрос отправлен через AJAX, и отдают данные в нужном формате — JSON или обычный редирект.

Метод error() предназначен для обработки ошибок. Он принимает три необязательных параметра:
  • $message — текст ошибки
  • $errors — массив ошибок для конкретных полей (например, ['username' => 'Не найден'])
  • $data — массив заполненных значений, которые нужно сохранить (например, ['username' => 'test'])
Если это AJAX-запрос, то вернётся JSON:
{
"success" : false,
"message" : $message,
"errors" : $errors,
}

Если обычный запрос, то произойдёт редирект назад с flash-сообщениями в сессии. Это то же самое, как если бы вы написали:
response()
    ->back() // перезагружаем страницу
    ->withErrors($errors) // добавляем сообщения об ошибках полей
    ->withInput($data) // добавляем заполненные данные
    ->with('error_message', $message); // добавляем ошибку формы

Метод success() используется при успешной авторизации. Он принимает два необязательных параметра:
  • $message — сообщение об успехе
  • $redirect — ссылка, на которую нужно перенаправить пользователя

Если это AJAX-запрос:
{
"success" : true,
"message" : $message,
"redirect" : $redirect,
}

Если это обычный запрос — произойдёт редирект, и в сессии будет установлено сообщение об успехе.
Под капотом:
response()
    ->redirect('/register') // делаем редирект на страницу /register
    ->with('success_message', $message); // добавляем сообщение

Заключение


С pbAuth вы получаете чистую архитектуру, гибкость маршрутов и контроллеров, удобную валидацию и безопасную авторизацию — без лишнего кода.

Установить пакет можно с моего репозитория:
  1. Переходим в меню установщика компонентов (Дополнения → Установщик).
  2. Переходим на вкладку «Провайдеры» и создаём нового провайдера.
  3. Выбираем созданного провайдера.
  4. После сохранения откроется список компонентов выбранного провайдера.

Поддержка


  • MODX 2 / 3
  • PHP ^7.4
Aleksandr Huz
16 июня 2025, 09:17
modx.pro
456
+10
Поблагодарить автора Отправить деньги

Комментарии: 1

Aleksandr Huz
25 июня 2025, 14:30
+1
[1.0.1-pl] — 2025-06-25

Добавлено
  • Загрузка аватарки
  • Автоматическое добавление пользователя в группу при регистрации
Улучшено
  • Валидация форм
Изменено
  • Импорт `Request` заменён на `Http\Request`
    Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
    1