提问人:miken32 提问时间:6/14/2019 更新时间:10/12/2019 访问量:1345
允许在 Laravel 中使用多个密码重置令牌
Allow multiple password reset tokens in Laravel
问:
Laravel(5.7)的密码重置系统的默认行为是在删除该用户的任何其他令牌后在表中创建一个新令牌。此行为是确定的,似乎不可配置。password_resets
\Illuminate\Auth\Passwords\DatabaseTokenRepository
protected function deleteExisting(CanResetPasswordContract $user)
{
return $this->getTable()->where('email', $user->getEmailForPasswordReset())->delete();
}
有太多的继承在进行,我无法弄清楚要扩展哪些类,以便我可以插入自己的规则。
是否可以允许在不入侵 Laravel 核心文件的情况下同时存在一定数量的密码重置?我需要扩展哪些课程?
答:
从 https://www.5balloons.info/extending-passwordbroker-class-laravel-5/ 复制
在 App\Providers
中创建 CustomPasswordResetServiceProvider
您需要创建一个类,我们将使用它来替换 Defaultnew 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
然后修改了函数 resolve 以返回我的类的实例CustomPasswordProvider
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
}
评论
\Illuminate\Auth\Passwords\DatabaseTokenRepository
是我需要覆盖的类; 是此类的实例。Illuminate\Auth\Passwords\PasswordBroker::$tokens
提供的答案并没有帮助我覆盖正确的类,但它确实给了我一些如何处理这个问题的想法。因此,我最终创建了三个类,它们都扩展了内置类:
DatabaseToken存储库
这是我从父类进行覆盖以允许我的自定义行为的地方;在创建新的重置令牌时保留两个最新的条目,并在执行重置时检查多个令牌。
<?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;
}
}
密码经纪人管理器
这只能确保使用我上面的自定义存储库类。该函数完全是从父类复制的,但当然,它位于不同的命名空间中。
<?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,
一切都很美。
评论