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.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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();
});

Method 2

If I recall correctly, you can use Dependency Injection to pass an appropriate Hasher to your Guard, so if you were to extend BcryptHasher and pass it, your issue would be solved.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x