Вопрос про xPDO
Здравствуй, сообщество!
Возникла необходимость записывать пароль пользователя как есть, не хэшируя. Предвосхищая возмущенные посты, скажу, что это необходимо для обмена с удаленной БД. Там УЖЕ пароли хранятся в хэшированном виде и, как вы понимаете, повторное хэширование кэшей ни к чему хорошему не приведет.
Покумекав и пошерстив исходники, нашел два варианта:
1. Расширить класс modHashing новым классом, в котором метод hash отдавал бы то же, что получил на входе, после этого временно сменить класс хэширования у пользователя на этот новый класс, установить пароль методом set, после чего сменить снова класс хэширования на тот, что используется на сайте постоянно.
2. У класса xPDOObject, наследником которого является и modUser, имеется метод _setRaw, который позволяет записывает в любое поле объекта информацию без предварительной обработки.
Первый метод мне не понравился: как-то сложно и не кошерно. У метода два есть ровно один, но критический недостаток — он объявлен с ключевым словом protected. Когда я пытаюсь вызвать этот метод из своего самописного класса, в который я передаю объект modUser, PHP плюется фатальной ошибкой.
Хотя в описании на php.net указано, что функции, объявленные protected, доступны только из самого объекта и его потомков. Я вызываю метод так:
В связи с этим, прошу уважаемое сообщество тыкнуть носом в способ, которым можно записать пароль в поле password, минуя процесс хэширования.
Заранее благодарю!
Возникла необходимость записывать пароль пользователя как есть, не хэшируя. Предвосхищая возмущенные посты, скажу, что это необходимо для обмена с удаленной БД. Там УЖЕ пароли хранятся в хэшированном виде и, как вы понимаете, повторное хэширование кэшей ни к чему хорошему не приведет.
Покумекав и пошерстив исходники, нашел два варианта:
1. Расширить класс modHashing новым классом, в котором метод hash отдавал бы то же, что получил на входе, после этого временно сменить класс хэширования у пользователя на этот новый класс, установить пароль методом set, после чего сменить снова класс хэширования на тот, что используется на сайте постоянно.
2. У класса xPDOObject, наследником которого является и modUser, имеется метод _setRaw, который позволяет записывает в любое поле объекта информацию без предварительной обработки.
Первый метод мне не понравился: как-то сложно и не кошерно. У метода два есть ровно один, но критический недостаток — он объявлен с ключевым словом protected. Когда я пытаюсь вызвать этот метод из своего самописного класса, в который я передаю объект modUser, PHP плюется фатальной ошибкой.
Хотя в описании на php.net указано, что функции, объявленные protected, доступны только из самого объекта и его потомков. Я вызываю метод так:
modUser $user->_setRaw('password', $password);
То есть вроде бы, вызывается метод из объекта modUser, а ошибка возникает всё равно. Пока, временно (поскольку сайт уже в боевом состоянии) изменил protected на public. При этом, я прекрасно понимаю, что так делать нельзя и вообще это до ближайшего обновления. В связи с этим, прошу уважаемое сообщество тыкнуть носом в способ, которым можно записать пароль в поле password, минуя процесс хэширования.
Заранее благодарю!
Комментарии: 17
Если нужно для обмена с удаленной БД — пиши пароли при создании юзера в отдельную таблицу плагином и не извращайся.
В "_user_settings", например.
$pass2 = $modx->newObject('modUserSetting');
$pass2->set('user',$profile->get('internalKey'));
$pass2->set('key','password2');
$pass2->set('value',$password);
$pass2->save();
По-моему, это еще менее изящно, чем смена класса хэширования на лету:))
Если я буду полученный пароль записывать в отдельную таблицу, мне придется всю авторизацию на сайте поменять, я не смогу использовать стандартные методы passwordMatches, changePassword и другие вкусности. Какая-то слишком дорогая цена для такой, в общем-то, простой задачи.
Если я буду полученный пароль записывать в отдельную таблицу, мне придется всю авторизацию на сайте поменять, я не смогу использовать стандартные методы passwordMatches, changePassword и другие вкусности. Какая-то слишком дорогая цена для такой, в общем-то, простой задачи.
А, мы, наверное, не поняли друг друга. Проблема не в том, что мне надо передать пароль удалённой БД (тут как раз всё просто), проблема в том, что я получаю хэш пароля из удалённой БД и мне его надо записать в БД сайта в обход хэширования.
В вопросе ты написал не совсем это.
Ты можешь указать у юзера свой класс, вместо modUser и расширить protected методы. Посмотри исходники HybridAuth — там так и сделано.
Ты можешь указать у юзера свой класс, вместо modUser и расширить protected методы. Посмотри исходники HybridAuth — там так и сделано.
Вот это уже больше подходит, спасибо!
Хотя всё равно придётся много где в моём коде внести изменения.
Странно, конечно, что этот метод объявлен защищенным… Его использование в моей ситуации здорово бы всё упростило:))
Хотя всё равно придётся много где в моём коде внести изменения.
Странно, конечно, что этот метод объявлен защищенным… Его использование в моей ситуации здорово бы всё упростило:))
Твой класс должен быть наследником modUser и тогда он сможет поменять логику работы _setRaw().
Тебе нужно для обмена с удаленной БД, а не для авторизации — или я неправильно понял?
Есть нормальная работа с юзерами с одной стороны, а есть таблица id — открытый пароль, с другой. По моему, это гораздо красивее, чем вламываться в нутро движка и все там курочить.
Есть нормальная работа с юзерами с одной стороны, а есть таблица id — открытый пароль, с другой. По моему, это гораздо красивее, чем вламываться в нутро движка и все там курочить.
Тебе нужно для обмена с удаленной БД, а не для авторизации — или я неправильно понял?Не совсем так. Я получаю хэш пароля от удалённой БД и потом использую его для авторизации на сайте. Причины, по которым устроено всё именно так, сложны и многогранны и многими гранями упираются в требования заказчика:))
Есть нормальная работа с юзерами с одной стороны, а есть таблица id — открытый пароль, с другой.Во-первых, не хотелось бы хранить пароль открытым, во-вторых, работа с юзерами и обмен с БД, как я написал выше, неразделимы. Я получаю хэш и он должен в итоге позволять пользователю авторизоваться во фронт-энде.
По моему, это гораздо красивее, чем вламываться в нутро движка и все там курочить.Абсолютно согласен, я это сделал только как временное решение, чтобы сайт мог продолжать работать, пока я разбираюсь.
Понял-понял, спасибо:)) Просто не успеваю так быстро отвечать:))
В итоге проблема решилась, на мой взгляд, изящнее, чем расширение класса modUser.
С версии 5.3 в php появились замыкания, а с версии 5.4 к ним добавили два метода: bind и bindTo. Подробнее о теории можно почитать тут.
Эти методы позваляют связать ваше замыкание с конкретным объектом, после чего замыканию становится доступен $this. То есть, фактически, мы можем добавить на лету произвольный метод классу и он будет выполняться в контексте класса.
В рассмотренном мной в заметке случае делается так:
С версии 5.3 в php появились замыкания, а с версии 5.4 к ним добавили два метода: bind и bindTo. Подробнее о теории можно почитать тут.
Эти методы позваляют связать ваше замыкание с конкретным объектом, после чего замыканию становится доступен $this. То есть, фактически, мы можем добавить на лету произвольный метод классу и он будет выполняться в контексте класса.
В рассмотренном мной в заметке случае делается так:
$user = $modx->user;
$method = function($name, $value)
{
$this->_setRaw($name, $value);
return $this->save();
}
$method = $method->bindTo($user, 'modUser');
$method('password', '12345');
Вуа-ля! Защищенный метод нам доступен из любого класса, поскольку выполняется как будто изнутри класса modUser.
А что мешает напрямую устанавливать значение свойства?
$user = & $modx->user;
$user->password = 12345;
$user->save();
И будет у вас в таблице в чистом виде пароль 12345.
Значения свойств не обязательно устанавливать через метод ->set(), где выполняются всякие модификации и т.п., их можно устанавливать напрямую, если само свойство у объекта уже есть. Это так же, как вы не установите $user->set('sudo', true);, так как там проверка, и если поле — sudo, то обламывается. Зато можно установить $user->sudo = true; $user->save();
$user = & $modx->user;
$user->password = 12345;
$user->save();
И будет у вас в таблице в чистом виде пароль 12345.
Значения свойств не обязательно устанавливать через метод ->set(), где выполняются всякие модификации и т.п., их можно устанавливать напрямую, если само свойство у объекта уже есть. Это так же, как вы не установите $user->set('sudo', true);, так как там проверка, и если поле — sudo, то обламывается. Зато можно установить $user->sudo = true; $user->save();
Ууу, класс! Вот это — то что надо! Спасибо большое за наводку.
Даже как-то неудобно — нагородил я тут огород с замыканиями, а самого простого способа не увидел:))
Даже как-то неудобно — нагородил я тут огород с замыканиями, а самого простого способа не увидел:))
Не за что.
Только еще момент: таким образом нельзя установить свойства, которых еще нет у объекта. К примеру, если у объекта нет свойства test, то нельзя сделать так: $object->test = $value; Свойства test у объекта после этого просто не будет. Вот здесь как раз и придется использовать $object->set($key, $val), чтобы свойство было создано. За эту магию отвечают ООП-методы __set() и __get() у класса xPDOObject. И вот здесь как раз кроется самое интересное (для этого смотрите сорцы xPDO github.com/modxcms/xpdo/blob/master/xpdo/om/xpdoobject.class.php#L739 ). Дело в том, что в методах __get() и __set() сразу прописана работа со связями getOne()/setOne() и т.д. и т.п.
К примеру, можно сделать так: $profile = $user->Profile, что будет равнозначно $profile = $user->getOne('Profile'). Таким образом можно получить свойство $user->Profile->email, даже если именно в этот момент еще не был получен связанный объект modProfile для этого пользователя. Или вот так:
$user = $modx->newObject('modUser', array(
«username» => «NewUser»,
));
$profile = $modx->newObject(«modUserProfile», array(
«email» => $someEmail,
«password» => $somePass,
));
$user->Profile = $profile;
$user->save();
И будут записаны в БД и данные пользователя (modUser), и данные его профиля (modUserProfile).
Только еще момент: таким образом нельзя установить свойства, которых еще нет у объекта. К примеру, если у объекта нет свойства test, то нельзя сделать так: $object->test = $value; Свойства test у объекта после этого просто не будет. Вот здесь как раз и придется использовать $object->set($key, $val), чтобы свойство было создано. За эту магию отвечают ООП-методы __set() и __get() у класса xPDOObject. И вот здесь как раз кроется самое интересное (для этого смотрите сорцы xPDO github.com/modxcms/xpdo/blob/master/xpdo/om/xpdoobject.class.php#L739 ). Дело в том, что в методах __get() и __set() сразу прописана работа со связями getOne()/setOne() и т.д. и т.п.
К примеру, можно сделать так: $profile = $user->Profile, что будет равнозначно $profile = $user->getOne('Profile'). Таким образом можно получить свойство $user->Profile->email, даже если именно в этот момент еще не был получен связанный объект modProfile для этого пользователя. Или вот так:
$user = $modx->newObject('modUser', array(
«username» => «NewUser»,
));
$profile = $modx->newObject(«modUserProfile», array(
«email» => $someEmail,
«password» => $somePass,
));
$user->Profile = $profile;
$user->save();
И будут записаны в БД и данные пользователя (modUser), и данные его профиля (modUserProfile).
Таким образом можно получить свойство $user->Profile->email, даже если именно в этот момент еще не был получен связанный объект modProfile для этого пользователя.Вот за эту наводку — отдельное огромное спасибо! Во мне вскипает очередная волна влюблённости в modx:))
Пожалуйста :)
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.