Скрипты для создания регистрации, авторизации и сброса пароля для Ajax и не только

При написании проекта на MODX 3.2.0 потребовались регистрация, авторизация и сброс пароля с Ajax, а также связь с другими таблицами базы данных.
В итоге получилось реализовать без компонентов Login и ajaxLogin.

В данной заметке решил выложить скрипты в виде шпаргалки:

Авторизация
В данном примере авторизация будет происходить через email.
/*
 * проверяем наличие пользователя и получаем его логин.
 */
if($modx->getCount('modUserProfile', array('email'=>$_POST['email'])) > 1){
    $user =  $modx->getObjectGraph('modUser','{"Profile":{},"UserSettings":{}}',[
        'modUser.username' => $_POST['email']
    ]);
}else{
    $user =  $modx->getObjectGraph('modUser','{"Profile":{},"UserSettings":{}}',[
        [
            'modUser.username' => $_POST['email']
        ],[
            'OR:Profile.email:=' => $_POST['email']
        ]
    ]);
}
$response = $modx->runProcessor('security/login',[
    'username' => $user->get('username'),
    'password' => $_POST['password'],
    'rememberme' => ($_POST['remember_me']==1) //Запомнить меня
]);
if($response->isError()) {
    return [
        'status' => 'errors',
        'result' => $response->getMessage()
    ];
}
return [
    'status'    => 'success',
    'result'    => 'Авторизация прошла успешно'
];

Регистрация
/*
 * проверяем, что email не занят.
 */
if($modx->getCount('modUserProfile', array(
    'email' => $_POST['email'],
)) > 1){
    $user = $modx->getObjectGraph('modUser','{"Profile":{},"UserSettings":{}}',[
        'modUser.username' => $_POST['email']
    ]);
}else{
    $user = $modx->getObjectGraph('modUser','{"Profile":{},"UserSettings":{}}',[
        [
            'modUser.username' => $_POST['email']
        ],[
            'OR:Profile.email:=' => $_POST['email']
        ]
    ]);
}
if($user){
    return [
        'status' => 'errors',
        'result' => "Почтовый ящик \"{$_POST['email']}\" уже используется. Вы можете либо войти под этой почтой, либо восстановить пароль (если вы его забыли), либо выбрать другой почтовый ящик для регистрации."
    ];
}
/*
 * Регистрируем нового пользователя
 */
$user = $modx->newObject('modUser');
$user->fromArray([
    'username' => $_POST['email'],
    'password' => $_POST['password'],
    'active' => 0,
]);
$profile = $modx->newObject('modUserProfile');
$profile->fromArray([
    'internalKey'   => $user->get('id'),
    'blockeduntil'  => 0,
    'blocked'       => 0,
    'blockedafter'  => 0,
    'fullname'      => $_POST['fullname'],
    'email'         => $_POST['email'],
    'mobilephone'   => $_POST['phone'],
]);
$user->addOne($profile);
if($user->save() === false){
    return [
        'status' => 'errors',
        'result' => "Произошла ошибка при попытке сохранить пользователя."
    ];
}
/*
 * Добавляем в группу Users[3] и в роль Users[3]
 */
$user->joinGroup(3,3);

/*
 * Отправляем письмо с сгенерированным паролем активации для подтверждения
 */
$password = $modx->user->generatePassword();
// pdoTools, не обязателен, только для формирования чанка письма
$pdo = $modx->getService('pdoTools');
$mailBody = $pdo->getChunk('tpl.email.register.activate',[
    'email'         => $profile->get('email'),
    'confirmUrl'    => $modx->makeUrl(1,'',[
        'reg'   => '1',
        'lp'    => rtrim(strtr(base64_encode($password), '+/', '-_'), '=');
        'lu'    => rtrim(strtr(base64_encode($user->get('username')), '+/', '-_'), '=');
    ],'full')
])

$mail = $modx->getService('mail', 'mail.modPHPMailer');
$mail->set(\modMail::MAIL_BODY, $mailBody);
$mail->set(\modMail::MAIL_FROM, $modx->getOption('emailsender');
$mail->set(\modMail::MAIL_FROM_NAME,$modx->getOption('site_name');
$mail->set(\modMail::MAIL_SENDER, $modx->getOption('emailsender');
$mail->set(\modMail::MAIL_SUBJECT, 'Спасибо за регистрацию. Пожалуйста, активируйте свой аккаунт!');
$mail->address('to', $profile->get('email'), $profile->get('fullname'));
$replyTo = $modx->getOption('emailReplyTo');
if (!empty($replyTo)) {
    $mail->address('reply-to', $replyTo);
}
$mail->setHTML(true);
$sent = $mail->send();
if (!$sent) {
    $modx->log(modX::LOG_LEVEL_ERROR, 'Произошла ошибка при отправке email. '.print_r($mail->mailer->ErrorInfo, true));
}
$mail->reset();

/*
 * Сохраняет в регистре сгенерированный пароль активации
 */
$modx->getService('registry', 'registry.modRegistry');
$modx->registry->addRegister('login','registry.modFileRegister');
$modx->registry->login->connect();
$modx->registry->login->subscribe('/useractivation/');
$modx->registry->login->send('/useractivation/',[
    $user->get('username') => $password
],[
    'ttl' => 180*60, //если за 3 часа не активировали - пароль активации удаляется.
]);
$user->set('cachepwd',md5($password));
if ($user->save() === false) {
    $modx->log(modX::LOG_LEVEL_ERROR,'Не удалось обновить cachepwd для активации пользователя: '.$user->get('username'));
}

return [
    'status'    => 'success',
    'result'    => 'Паспортные данные успешно обновлены'
];

Письмо для активации учётной записи
Чанк tpl.email.register.activate для письма:
<p>{$fullname},</p>
<p>Спасибо за регистрацию! Чтобы активировать вашу новую учетную запись, пожалуйста, перейдите по следующей ссылке:</p>
<p><a href="{$confirmUrl}">{$confirmUrl}</a></p>
<p>Если вы не запрашивали это сообщение, пожалуйста, проигнорируйте его.</p>
<p>Спасибо,
<em>Администратор сайта</em></p>

Сброс пароля
/*
 * проверяем наличие пользователя и получаем его логин.
 */
if($modx->getCount('modUserProfile', array(
    'email' => $_POST['email'],
)) > 1){
    $user =  $modx->getObjectGraph('modUser','{"Profile":{},"UserSettings":{}}',[
        'modUser.username' => $_POST['email']
    ]);
}else{
    $user =  $modx->getObjectGraph('modUser','{"Profile":{},"UserSettings":{}}',[
        [
            'modUser.username' => $_POST['email']
        ],[
            'OR:Profile.email:=' => $_POST['email']
        ]
    ]);
}
if($user){
    $profile = $user->getOne('Profile');
/*
 * Отправляем письмо с сгенерированным паролем активации для подтверждения
 */
    $password = $modx->user->generatePassword();
// pdoTools, не обязателен, только для формирования чанка письма
    $pdo = $modx->getService('pdoTools');
    $mailBody = $pdo->getChunk('tpl.email.password.forgot',[
        'fullname'      => $profile->get('fullname'),
        'email'         => $profile->get('email'),
        'password'      => $password,
        'confirmUrl'    => $modx->makeUrl(1,'',[
            'rpw'   => '1',
            'lp'    => rtrim(strtr(base64_encode($password), '+/', '-_'), '=');
            'lu'    => rtrim(strtr(base64_encode($user->get('username')), '+/', '-_'), '=');
        ],'full')
    ])

    $mail = $modx->getService('mail', 'mail.modPHPMailer');
    $mail->set(\modMail::MAIL_BODY, $mailBody);
    $mail->set(\modMail::MAIL_FROM, $modx->getOption('emailsender');
    $mail->set(\modMail::MAIL_FROM_NAME,$modx->getOption('site_name');
    $mail->set(\modMail::MAIL_SENDER, $modx->getOption('emailsender');
    $mail->set(\modMail::MAIL_SUBJECT, 'Адрес электронной почты для восстановления пароля');
    $mail->address('to', $profile->get('email'), $profile->get('fullname'));
    $replyTo = $modx->getOption('emailReplyTo');
    if (!empty($replyTo)) {
        $mail->address('reply-to', $replyTo);
    }
    $mail->setHTML(true);
    $sent = $mail->send();
    if (!$sent) {
        $modx->log(modX::LOG_LEVEL_ERROR, 'Произошла ошибка при отправке email. '.print_r($mail->mailer->ErrorInfo, true));
    }
    $mail->reset();
    
    $modx->cacheManager->set('login/resetpassword/'.md5($user->get('id').':'.$user->get('username')),$password);

    return [
        'status'    => 'success',
        'result'    => 'Пароль успешно сброшен'
    ];
}else{
    return [
        'status' => 'errors',
        'result' => "Почтовый ящик \"{$_POST['email']}\" не найден. Проверьте корректность email и повторите попытку"
    ];
}

Письмо для сброса пароля
Чанк tpl.email.password.forgot для письма:
<p>Здравствуйте {$fullname}.</p>
<p>Чтобы активировать ваш новый пароль, пожалуйста, перейдите по ссылке:</p>
<p><a href="{$confirmUrl}">{$confirmUrl}</a></p>
<p>Если подтверждение пройдет успешно, вы сможете использовать следующий пароль для входа:</p>
<p><strong>Пароль:</strong> {$password}</p>
<p>Если вы не запрашивали это сообщение, пожалуйста, игнорируйте его.</p>
<p>Спасибо.
<em>Администрация сайта [[++site_name]]</em></p>

Скрипт для активации новой учетной записи и нового пароля
Данный скрипт вставляем в новый сниппет; после сохранения вставляем сниппет во все шаблоны или в определённый шаблон.
if(!empty($_REQUEST['lp']) && !empty($_REQUEST['lu'])){
    if(!$modx->user->isAuthenticated()){
        $user = $modx->getObject('modUser',[
            'username' => base64_decode(str_pad(strtr($_REQUEST['lu'], '-_', '+/'), strlen($_REQUEST['lu']) % 4, '=', STR_PAD_RIGHT));
        ]);
        if ($user !== null){
            $password = base64_decode(str_pad(strtr($_REQUEST['lp'], '-_', '+/'), strlen($_REQUEST['lp']) % 4, '=', STR_PAD_RIGHT));
            if ($_REQUEST['reg'] == '1' &&  $user->get('active') == '0') {
                $modx->getService('registry', 'registry.modRegistry');
                $modx->registry->addRegister('login','registry.modFileRegister');
                $modx->registry->login->connect();
                $modx->registry->login->subscribe('/useractivation/'.$user->get('username'));
                $msgs = $modx->registry->login->read();
                if (empty($msgs)) $modx->sendErrorPage();
                $found = false;
                foreach ($msgs as $msg) {
                    if ($msg == $password) {
                        $found = true;
                    }
                }
                if ($found) {
                    $user->set('active',1);
                    $user->_fields['cachepwd'] = '';
                    $user->setDirty('cachepwd');
                    
                    if ($user->save() === false) {
                        $modx->log(modX::LOG_LEVEL_ERROR,'Не удалось активировать пользователя: '.$user->get('username'));
                    }else{
                        $modx->user =& $user;
                        $modx->getUser();
                        $modx->user->addSessionContext($modx->context->get('key'));
                    //После активации авторизуем пользователя и запускаем редирект на главную страницу
                        $modx->sendRedirect($modx->makeUrl(1,'','','full'));
                    }
                }
            }elseif($_REQUEST['rpw'] == '1'){
                $cacheKey = 'login/resetpassword/'.md5($user->get('id').':'.$user->get('username'));
                $cachePass = $modx->cacheManager->get($cacheKey);
                if ($cachePass == $password) {
                    $user->set('password',$password);
                    if($user->save() === false) {
                        $modx->log(modX::LOG_LEVEL_ERROR,'Не удалось сбросить пароль: '.$user->get('username'));
                    }else{
                        $modx->cacheManager->delete($cacheKey);
                    //После активации пользователя и запускаем редирект на страницу авторизации
                        $modx->sendRedirect($modx->makeUrl(1,'',['rpw'=>'2'],'full'));
                    }
                }
            }
        }
    }
}

Скрипт для выхода из аккаунта
Данный скрипт вставляем в новый сниппет; после сохранения вставляем сниппет во все шаблоны.
/*
 * При переходе по ссылке /?logout=1 пользователь выйдет из аккаунта.
 */
if(!empty($_REQUEST['logout']) && $_REQUEST['logout']==1){
    if($modx->user->isAuthenticated()){
        $response = $modx->runProcessor('security/logout');
        if ($response->isError()) {
            $modx->log(modX::LOG_LEVEL_ERROR,'При попытки выйти из системы возникла ошибка: '.$response->getMessage());
        }
    }
}
Сергей
Сергей
2 часа назад
modx.pro
9

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

Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
0