DatabaseTokenRepository

DatabaseTokenRepository

本文介绍了在Laravel中允许多个密码重置令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Laravel(5.7)的密码重置系统的默认行为是在删除该用户的任何其他令牌后,在password_resets表中创建一个新令牌.此行为在\Illuminate\Auth\Passwords\DatabaseTokenRepository中确定,并且似乎不可配置.

The default behaviour of Laravel (5.7)'s password reset system is to create a new token in the password_resets table after deleting any others for that user. This behaviour is determined in \Illuminate\Auth\Passwords\DatabaseTokenRepository and it doesn't seem configurable.

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

继承如此之多,我无法弄清楚要扩展的类,所以我可以插入自己的规则.

There's so much inheritance going on, I can't figure out what classes to extend so I can insert my own rules.

是否可以在不侵入Laravel核心文件的情况下允许一定数量的密码重置同时存在?我需要扩展哪些课程?

Is it possible to allow a certain number password resets to exist simultaneously without hacking into the Laravel core files? What classes do I need to extend?

推荐答案

提供的答案并不能帮助我覆盖正确的类,但是确实为我提供了一些解决方法.因此,我最终创建了三个类,所有这些类都扩展了内置类:

The answer provided did not help me override the correct class, but it did give me some ideas how to approach this. So I ended up creating three classes, all of which extend built-in classes:

DatabaseTokenRepository

这是我从父类以允许我的自定义行为;创建新的重置令牌时,请保留两个最新条目,并在执行重置时检查多个令牌.

This is where I did the overrides from the parent class to allow my custom behaviour; keep the two most recent entries when creating a new reset token, and check multiple tokens when performing the reset.

<?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

这只是确保使用我上面的自定义存储库类.该函数是从父类,但是当然是在其他命名空间中.

This just ensures that my custom repository class above is used. The function is copied exactly from the parent class, but is, of course, in a different namespace.

<?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

再次,仅确保返回自定义类.同样,只有名称空间从原始.

Again, just ensuring that the custom class is returned. Again, only the namespace changes from the original.

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

最后,应用程序配置已更新为使用我的提供程序,而不是原始的提供程序:

Finally, the application config is updated to use my provider instead of the original:

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

一切正常.

这篇关于在Laravel中允许多个密码重置令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-11 17:35