Разрешить множественные токены сброса пароля в Laravel - PullRequest
0 голосов
/ 14 июня 2019

По умолчанию система сброса пароля Laravel (5.7) создает новый токен в таблице password_resets после удаления любых других для этого пользователя. Это поведение определяется в \Illuminate\Auth\Passwords\DatabaseTokenRepository, и оно не кажется настраиваемым.

protected function deleteExisting(CanResetPasswordContract $user)
{
    return $this->getTable()->where('email', $user->getEmailForPasswordReset())->delete();
}

Происходит так много наследования, я не могу понять, какие классы расширить, чтобы я мог вставить свои собственные правила.

Можно ли разрешить одновременное восстановление определенного количества паролей без взлома файлов ядра Laravel? Какие классы мне нужно продлить?

Ответы [ 2 ]

0 голосов
/ 14 июня 2019

Предоставленный ответ не помог мне переопределить правильный класс, но он дал мне некоторые идеи, как подойти к этому.В итоге я создал три класса, каждый из которых расширяет встроенные классы:

DatabaseTokenRepository

Здесь я сделал переопределения, чтобы разрешить свое пользовательское поведение;удаляйте только три самые старые записи при создании нового токена сброса и проверяйте несколько токенов при выполнении сброса.

<?php

namespace App\Services;

use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Auth\Passwords\DatabaseTokenRepository as DatabaseTokenRepositoryBase;

class DatabaseTokenRepository extends DatabaseTokenRepositoryBase
{
    /**
     * Create a new token record.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @return string
     */
    public function create(CanResetPasswordContract $user)
    {
        $email = $user->getEmailForPasswordReset();

        $this->deleteSomeExisting($user);

        // We will create a new, random token for the user so that we can e-mail them
        // a safe link to the password reset form. Then we will insert a record in
        // the database so that we can verify the token within the actual reset.
        $token = $this->createNewToken();

        $this->getTable()->insert($this->getPayload($email, $token));

        return $token;
    }

    /**
     * Determine if a token record exists and is valid.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @param  string  $token
     * @return bool
     */
    public function exists(CanResetPasswordContract $user, $token)
    {
        $records = $this->getTable()
            ->where("email", $user->getEmailForPasswordReset())
            ->get();

        foreach ($records as $record) {
            if (
               ! $this->tokenExpired($record->created_at) &&
                 $this->hasher->check($token, $record->token)
            ) {
                return true;
            }
        }
        return false;
    }

    /**
     * Delete SOME existing reset tokens from the database.
     *
     * @param  \Illuminate\Contracts\Auth\CanResetPassword  $user
     * @return int
     */
    protected function deleteSomeExisting($user)
    {
        // TODO: make this configurable in app config
        $limit = 3;
        $records = $this->getTable()
            ->where("email", $user->getEmailForPasswordReset())
            ->orderBy("created_at");
        $ct = $records->count() - $limit + 1;
        return ($ct > 0) ? $records->limit($ct)->delete() : 0;
    }
}

PasswordBrokerManager

Это просто гарантирует, что мой пользовательскийкласс хранилища выше используется.Функция копируется точно из родительского класса, но, конечно, в другом пространстве имен.

<?php

namespace App\Services;

use Illuminate\Support\Str;
use Illuminate\Auth\Passwords\PasswordBrokerManager as PasswordBrokerManagerBase;

class PasswordBrokerManager extends PasswordBrokerManagerBase
{
    /**
     * Create a token repository instance based on the given configuration.
     *
     * @param  array  $config
     * @return \Illuminate\Auth\Passwords\TokenRepositoryInterface
     */
    protected function createTokenRepository(array $config)
    {
        $key = $this->app['config']['app.key'];

        if (Str::startsWith($key, 'base64:')) {
            $key = base64_decode(substr($key, 7));
        }

        $connection = $config['connection'] ?? null;

        return new DatabaseTokenRepository(
            $this->app['db']->connection($connection),
            $this->app['hash'],
            $config['table'],
            $key,
            $config['expire']
        );
    }
}

PasswordResetServiceProvider

Опять же, просто гарантируя, что пользовательскийкласс возвращается.Опять же, меняется только пространство имен.

<?php

namespace App\Providers;

use App\Services\PasswordBrokerManager;
use Illuminate\Auth\Passwords\PasswordResetServiceProvider as PasswordResetServiceProviderBase;

class PasswordResetServiceProvider extends PasswordResetServiceProviderBase
{
    /**
     * Register the password broker instance.
     *
     * @return void
     */
    protected function registerPasswordBroker()
    {
        $this->app->singleton("auth.password", function ($app) {
            return new PasswordBrokerManager($app);
        });

        $this->app->bind("auth.password.broker", function ($app) {
            return $app->make("auth.password")->broker();
        });
    }
}

Наконец, конфигурация приложения обновляется:

    // Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
    App\Providers\PasswordResetServiceProvider::class,

И все прекрасно работает.

0 голосов
/ 14 июня 2019

Скопировано из https://www.5balloons.info/extending-passwordbroker-class-laravel-5/

Создать CustomPasswordResetServiceProvider внутри App\Providers

Вам необходимо создать класс new CustomPasswordResetServiceProvider, который мы будем использовать для заменыпо умолчанию PasswordResetServiceProvider

namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\CustomPasswordBrokerManager; 
class CustomPasswordResetServiceProvider extends ServiceProvider{
    protected $defer = true;

    public function register()
    {
        $this->registerPasswordBrokerManager();
    }

    protected function registerPasswordBrokerManager()
    {
        $this->app->singleton('auth.password', function ($app) {
            return new CustomPasswordBrokerManager($app);
        });
    }

    public function provides()
    {
        return ['auth.password'];
    }
}

Заменить поставщика услуг в app/config.php

//Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,

App\Providers\CustomPasswordResetServiceProvider::class,

Создать новый CustomPasswordBrokerManager класс

Создайте новый класс CustomPasswordBrokerManager и в каталоге App/Services и скопируйте все содержимое PasswordBrokerManager, которое расположено в Illuminate\Auth\Passwords\PasswordBrokerManager.php

Затем изменили функцию resol для возврата экземпляра моегоCustomPasswordProvider class

protected function resolve($name)
{
    $config = $this->getConfig($name);
    if (is_null($config)) {
        throw new InvalidArgumentException("Password resetter [{$name}] is not defined.");
    }

    return new CustomPasswordBroker(
        $this->createTokenRepository($config),
        $this->app['auth']->createUserProvider($config['provider'])
);
}

Создать CustomPasswordBroker

Наконец, теперь вы можете создать свой новый класс CustomPasswordBroker в каталоге App/Services, который расширяет значение по умолчанию PasswordBroker класс расположен в Illuminate\Auth\Passwords\PasswordBroker

use Illuminate\Auth\Passwords\PasswordBroker as BasePasswordBroker;    

class CustomPasswordBroker extends BasePasswordBroker    
{    
// override the functions that you need here    
}
...