Авторизация / регистрация в MODx
Как это работает?
Авторизация в modx работает на основе сессий. Встроенный механизм жуток и непонятен даже посвященным. Мы будет ее делать свой вариант на допольнительных полях и куках.
Авторизация:
- Если пользователь найден
- Если у него нет доп. поля acess_token, то создаем и сохраняем
- Пишем в куки токен
- Возвращаем поля пользователя и токен
- Токен сохраняем в локальном хранилище в браузере
Регистрация:
- Если пользователя с такой почтой не существует
- Регаем его, создаем email_verify_token, сохраняем в доп. (extended) поля
- Отправляем письмо на почту с ссылкой на созданную страничку, где мы проверим токен
- Если среди пользователей такой токен есть, то мы пользователя активируем
- email_verify_token удаляем из доп. полей
Получение инфы от авторизованного пользователя на бэкенде:
- После авторизации в куках у нас должен быть токен
- По токену ищем пользователя
- Возвращаем нужные данные или что-то модифицируем на сервере (если у пользователя есть персональная скидка на товар, например)
Получение инфы по юзеру по запросу с фронта xmlHttpRequest
- Из локального хранилища берем токен
- Добавляем в body
- На стороне сервера дергаем сниппет с функцией поиска юзера по токену
- Если пользователь найден, возвращаем его данные
Нюансы:
Это не совсем JWT-токен. Хотя можно использовать и эту библиотечку и генерить 2 токена access и refresh и определить время "протухания" accessToken-а. Либо воспользоваться функцией рандомной строки и сделать тоже самое, но руками
Токены хранятся в расширенных (дополнительных, extended) полях пользователя, точнее в профиле. Так же там можно хранить вообще че угодно, т.к. они хранятся в виде json-объекта. Но они не индексируются, поэтому на больших объемах делать поиск будет вероятно долго.
Подробнее с примерами кода
Проверка, существует ли пользователь:
Предполагается, что фронт будет передавать логин/пароль и action через xmlHttpRequest. По запросу, например, на эндпоинт "/api/user". В modx будут созданы соотвествующие ресурсы. В соотв. ресурсе с помощью fenom и switch мы будем перебирать action, и дергать соотв. сниппет, передавая ему тело запроса post
{switch $.post.action}
{case 'login'}
{'login' | snippet : ['data' => $.post]}
{/switch}
Сниппет login:
$data = json_decode($data['data'],true);
$data = array(
'username' => $data['username'],
'password' => $data['password'],
'rememberme' => 1,
'login_context' => 'web');
$response = $modx->runProcessor('/security/login', $data);
if ($response->isError()) {
$arr = [
"success" => false,
"message" => $response->getMessage()
];
header("HTTP/1.1 422 Неверный логин или пароль");
return json_encode($arr);
}
$user = $modx->getObject('modUser', array('username' => $data['username']));
Сниппет поиска пользователя по токену:
Принимает $token в качестве параметра
$users = $modx->getCollection('modUser');
foreach($users as $user){
if(!$user) return false;
$u = $user->toArray();
$user = $modx->getObject('modUser', array('id' => $u['id']));
$profile = $user->getOne('Profile');
$fields = $profile->get('extended');
if($fields['access_token'] == $token){
return $user;
}
}
return false;
Установка куки при успешной авторизации:
setcookie("access_token",'your_access_token', time()+3600,"/");
Удаление куки при логауте:
setcookie('access_token', '', 1,'/');
$modx->user = $modx->getObject('modUser', 0);