Skip to content
Advertisement

How to edit Laravel 7 AbstractHasher or BcryptHasher?

I’m having some problems trying to extend or change a part of the Laravel Framework. Simply I cannot figure out where I can add or edit so that my changes will not be made in the vendor folder.

Essentially my issue was implementing Password Reset functionality to my React/Laravel application. I use inertia to post the reset password form, and it gives the error as follows:

ErrorException password_verify() expects parameter 1 to be string, array given

I use Bcrypt to hash the passwords, so as a workaround I added a couple lines of code to the check function of vendor/laravel/framework/src/Illuminate/Hashing/BcryptHasher.php:

    if (is_array($value)) {
       $value = array_values($value)[0];
  }

So now the whole function looks like this:

public function check($value, $hashedValue, array $options = [])
{
    if ($this->verifyAlgorithm && $this->info($hashedValue)['algoName'] !== 'bcrypt') {
        throw new RuntimeException('This password does not use the Bcrypt algorithm.');
    }
    if (is_array($value)) {
        $value = array_values($value)[0];
    }
    return parent::check($value, $hashedValue, $options);
}

I can also make the same change in the parent, AbstractHasher, within its check function and this also resolves the error.

This works, but I need to find a solution to implement this fix without making the changes inside the vendor folder. I deploy the app to google app engine so the changes within the vendor folder will not work in my situation. I just need to know how I can either extend or overwrite the BcryptHasher.php or AbstractHasher.php file properly.

Note: This is my first post here, so hopefully I did not format the message too poorly. If any additional information is required I will provide it. Thanks in advance.

Advertisement

Answer

To resolve the issue, I adapted @apokryfos answer How to change login hash bcrypt to hash256 to work with BcryptHasher instead of trying to add a new hasher such as Sha256.

To do this I made the following changes:

In config/hashing.php Set the driver as custombcrypt for my implementation.

‘driver’ => ‘custombcrypt’,

In app folder

I created a folder named Libraries to hold my custom hasher classes. This folder can be named anything.

In created Libraries folder at app/Libraries

I created a file CustomBcryptHasher.php

<?php

namespace AppLibraries;

use IlluminateHashingBcryptHasher;
use RuntimeException;

class CustomBcryptHasher extends BcryptHasher
{
    /**
     * Check the given plain value against a hash.
     *
     * @param  string  $value
     * @param  string  $hashedValue
     * @param  array  $options
     * @return bool
     *
     * @throws RuntimeException
     */
    public function check($value, $hashedValue, array $options = [])
    {
        if ($this->verifyAlgorithm && $this->info($hashedValue)['algoName'] !== 'bcrypt') {
            throw new RuntimeException('This password does not use the Bcrypt algorithm.');
        }
        if (is_array($value)) {
            $value = array_values($value)[0];
        }
        return parent::check($value, $hashedValue, $options);
    }

}

The most important part of this file is this small portion near the bottom

    if (is_array($value)) {
       $value = array_values($value)[0];
  }

This checks if the value is an array, and if so will extract the first value and use this for the Bcrypt check.

In created Libraries folder at app/Libraries I add created a file named Hash.php which is a copy of /vendor/laravel/framework/src/Illuminate/Support/Facades/Hash.php

<?php

namespace IlluminateSupportFacades;

/**
 * @method static array info(string $hashedValue)
 * @method static bool check(string $value, string $hashedValue, array $options = [])
 * @method static bool needsRehash(string $hashedValue, array $options = [])
 * @method static string make(string $value, array $options = [])
 *
 * @see IlluminateHashingHashManager
 */
class Hash extends Facade
{
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'hash';
    }
}

In app/Providers I edited the AuthServiceProvider.php to return my CustomBcryptHasher.php when the custombcrypt driver is called.

To do so, I added this code to the boot() function:

Hash::extend('custombcrypt', function () {
    return new CustomBcryptHasher();
});
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement