In some projects developers may face the problem of migrating the data from various other platforms to Magento 2: for example, the site may have previously worked on another CMS system, but we want to keep the already existing products, users and other entities in it. At the same time, when migrating users, we can migrate all the data to Magento except for password hashes, because they are encrypted differently in another system: use a different algorithm, another combination of salt and the password itself, etc.
As a result, after such a migration, a customer will not be able to log into the updated site and will have to use the password recovery system. How can we avoid it without creating unnecessary inconveniences for a customer? Let’s see how it works using the example of migrating customers from WordPress.
First of all, we save the necessary user data from WordPress to our Magento database, including password hashes in the form they were received from WordPress:
The idea behind it is to change the password hash obtained from the previous system into the native Magento one when we have access to the unhashed password, i.e. while logging in. To do this, create an observer using the controller_action_predispatch_customer_account_loginPost event, which is called before the \Magento\Customer\Controller\Account\LoginPost controller. For this purpose we should create a new module, and inside it — the /app/code/YourVendor/PasswordHashConverter/etc/events.xml file:
1 2 3 4 5 6 |
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> <event name="controller_action_predispatch_customer_account_loginPost"> <observer name="customer_upgrade_password" instance="YourVendor/PasswordHashConverter\Observer\UpgradeCustomerPasswordObserver" /> </event> </config> |
Besides that, we will need to compare the password entered by a customer with the original hash from WordPress. We do it with the help of the Portable PHP hash framework, used in WordPress for these purposes. Save it to our module as /app/code/YourVendor/PasswordHashConverter/PasswordHash.php. For further use in our code, write it to /app/code/YourVendor/etc/di.xml, specifying its signature of the two received parameters: iteration_count_log2 and portable_hashes:
1 2 3 4 5 6 7 8 9 |
<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <type name="YourVendor/PasswordHashConverter\PasswordHash"> <arguments> <argument name="iteration_count_log2" xsi:type="number">8</argument> <argument name="portable_hashes" xsi:type="boolean">true</argument> </arguments> </type> </config> |
It only remains to create an observer that will implement the functionality we need.
/app/code/YourVendor/PasswordHashConverter/Observer/UpgradeCustomerPasswordObserver.php:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
<?php namespace YourVendor/PasswordHashConverter\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Customer\Model\ResourceModel\CustomerRepository; use Magento\Customer\Model\CustomerRegistry; use YourVendor/PasswordHashConverter\PasswordHash; class UpgradeCustomerPasswordObserver implements ObserverInterface { /** * Encryption model * * @var EncryptorInterface */ protected $encryptor; /** @var \BelVG\Encryption\PasswordHash class from Wordpress */ protected $WpPasswordHasher; /** * @var CustomerRegistry */ protected $customerRegistry; /** * @var CustomerRepository */ protected $customerRepository; public function __construct( EncryptorInterface $encryptor, CustomerRegistry $customerRegistry, CustomerRepository $customerRepository, PasswordHash $WpPasswordHasher ) { $this->encryptor = $encryptor; $this->WpPasswordHasher = $WpPasswordHasher; $this->customerRegistry = $customerRegistry; $this->customerRepository = $customerRepository; } /** * Upgrade customer password hash when customer has logged in * * @param \Magento\Framework\Event\Observer $observer * @return void */ public function execute(\Magento\Framework\Event\Observer $observer) { $requestParams = $observer->getEvent()->getData('request')->getParams(); $username = $requestParams['login']['username']; $password = $requestParams['login']['password']; try { /** @var \Magento\Customer\Api\Data\CustomerInterface */ $customer = $this->customerRepository->get($username); $customerSecure = $this->customerRegistry->retrieveSecureData($customer->getId()); $hash = $customerSecure->getPasswordHash(); if ($this->WpPasswordHasher->CheckPassword($password, $hash)) { $customerSecure->setPasswordHash($this->encryptor->getHash($password, true)); $this->customerRepository->save($customer); } } catch (\Exception $e) { } } } |
The Observer checks if the password matches the old hash from WordPress, and if it finds one, it converts the password to the Magento format. If the match is not found (we have already changed the hash to a new one, or simply entered a wrong password), our observer will not do anything (the catch block in its implementation is left empty for this purpose). The native Magento mechanism for validating the login and password will be launched after the execution of our code, and thus the authorization will be completed as usual.
Magento Custom Development
Take your online store to the next level with BelVG Magento Custom Development
Visit the pageAs a result, for all imported and logged users the password will be encrypted according to the Magento standards, and will not differ from the newly registered ones:
The described mechanism is suitable not only for WordPress but also for any other engine, from which we can extract the password hashing mechanism and use it for verification.
Magento 2 Migration
Take your online store to the next level with BelVG Magento 2 Migration
Visit the page
Thanks for the article. perfect
Wow! what a article! Very helpful.
Saved me a lot <3
Hi, Anton
Thank you, I appreciate that!
The cool article. This is useful. Thank you!