Вопрос про 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
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
Если я буду полученный пароль записывать в отдельную таблицу, мне придется всю авторизацию на сайте поменять, я не смогу использовать стандартные методы passwordMatches, changePassword и другие вкусности. Какая-то слишком дорогая цена для такой, в общем-то, простой задачи.
Ты можешь указать у юзера свой класс, вместо modUser и расширить protected методы. Посмотри исходники HybridAuth — там так и сделано.
Хотя всё равно придётся много где в моём коде внести изменения.
Странно, конечно, что этот метод объявлен защищенным… Его использование в моей ситуации здорово бы всё упростило:))
Есть нормальная работа с юзерами с одной стороны, а есть таблица id — открытый пароль, с другой. По моему, это гораздо красивее, чем вламываться в нутро движка и все там курочить.
Во-первых, не хотелось бы хранить пароль открытым, во-вторых, работа с юзерами и обмен с БД, как я написал выше, неразделимы. Я получаю хэш и он должен в итоге позволять пользователю авторизоваться во фронт-энде.
Абсолютно согласен, я это сделал только как временное решение, чтобы сайт мог продолжать работать, пока я разбираюсь.
С версии 5.3 в php появились замыкания, а с версии 5.4 к ним добавили два метода: bind и bindTo. Подробнее о теории можно почитать тут.
Эти методы позваляют связать ваше замыкание с конкретным объектом, после чего замыканию становится доступен $this. То есть, фактически, мы можем добавить на лету произвольный метод классу и он будет выполняться в контексте класса.
В рассмотренном мной в заметке случае делается так:
Вуа-ля! Защищенный метод нам доступен из любого класса, поскольку выполняется как будто изнутри класса modUser.
Fi1osof$user = & $modx->user;
$user->password = 12345;
$user->save();
И будет у вас в таблице в чистом виде пароль 12345.
Значения свойств не обязательно устанавливать через метод ->set(), где выполняются всякие модификации и т.п., их можно устанавливать напрямую, если само свойство у объекта уже есть. Это так же, как вы не установите $user->set('sudo', true);, так как там проверка, и если поле — sudo, то обламывается. Зато можно установить $user->sudo = true; $user->save();
Даже как-то неудобно — нагородил я тут огород с замыканиями, а самого простого способа не увидел:))
Fi1osofТолько еще момент: таким образом нельзя установить свойства, которых еще нет у объекта. К примеру, если у объекта нет свойства 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).
Fi1osof