如果您想覆盖 \Illuminate\Auth\Passwords\DatabaseTokenRepository 方法的行为,您必须构建自己的令牌存储库。
以前您可以覆盖现有存储库中的方法,但这些方法现在是 protected。不幸的是,这基本上意味着从vendor/laravel/framework/src/Illuminate/Auth/Passwords/DatabaseTokenRepository.php 复制和粘贴整个存储库代码。
创建这些文件:
app/Auth/DatabaseTokenRepository.php
<?php
namespace App\Auth;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
class DatabaseTokenRepository implements TokenRepositoryInterface
{
//
// Override these methods
//
public function __construct(
protected ConnectionInterface $connection,
protected HasherContract $hasher,
protected string $table
protected string $hashKey,
protected int $expires = 60,
protected int $throttle = 60
)
{
// PHP 8 constructor promotion, not much code here!
$this->expires = $expires * 60;
}
public function create(CanResetPasswordContract $user)
{
$email = $user->getEmailForPasswordReset();
$mobile = $user->getMobileForPasswordReset();
$this->deleteExisting($user);
$token = $this->createNewToken();
$this->getTable()->insert($this->getPayload($email, $mobile, $token));
return $token;
}
protected function deleteExisting(CanResetPasswordContract $user)
{
return $this->getTable()
->where("email", $user->getEmailForPasswordReset())
->orWhere("mobile", $user->getMobileForPasswordReset())
->delete();
}
protected function getPayload($email, $mobile, $token): array
{
return [
"email" => $email,
"mobile" => $mobile,
"token" => $this->hasher->make($token),
"created_at" => new Carbon(),
];
}
public function exists(CanResetPasswordContract $user, $token)
{
$record = (array) $this->getTable()
->where("email", $user->getEmailForPasswordReset())
->orWhere("mobile", $user->getMobileForPasswordReset())
->first();
return $record &&
! $this->tokenExpired($record["created_at"]) &&
$this->hasher->check($token, $record["token"]);
}
public function recentlyCreatedToken(CanResetPasswordContract $user)
{
$record = (array) $this->getTable()
->where("email", $user->getEmailForPasswordReset())
->orWhere("mobile", $user->getMobileForPasswordReset())
->first();
return $record && $this->tokenRecentlyCreated($record['created_at']);
}
//
// Remaining methods are untouched
//
protected function tokenExpired($createdAt)
{
return Carbon::parse($createdAt)->addSeconds($this->expires)->isPast();
}
protected function tokenRecentlyCreated($createdAt)
{
if ($this->throttle <= 0) {
return false;
}
return Carbon::parse($createdAt)->addSeconds(
$this->throttle
)->isFuture();
}
public function delete(CanResetPasswordContract $user)
{
$this->deleteExisting($user);
}
public function deleteExpired()
{
$expiredAt = Carbon::now()->subSeconds($this->expires);
$this->getTable()->where('created_at', '<', $expiredAt)->delete();
}
public function createNewToken()
{
return hash_hmac('sha256', Str::random(40), $this->hashKey);
}
public function getConnection()
{
return $this->connection;
}
protected function getTable()
{
return $this->connection->table($this->table);
}
public function getHasher()
{
return $this->hasher;
}
}
现在您将需要使用此自定义令牌存储库而不是默认的。所以你必须重写另一个类。
app/Auth/PasswordBrokerManager.php
<?php
namespace App\Auth;
use Illuminate\Support\Str;
use Illuminate\Auth\Passwords\PasswordBrokerManager as PasswordBrokerManagerBase;
class PasswordBrokerManager extends PasswordBrokerManagerBase
{
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 an instance of your new repository
// it's in the same namespace, no need to alias it
return new DatabaseTokenRepository(
$this->app['db']->connection($connection),
$this->app['hash'],
$config['table'],
$key,
$config['expire']
);
}
}
现在您已经创建了一个自定义代理来使用您的自定义存储库。您需要一个新的服务提供商来使用它。
app/Providers/PasswordResetServiceProvider.php
<?php
namespace App\Providers;
use App\Auth\PasswordBrokerManager;
use Illuminate\Auth\Passwords\PasswordResetServiceProvider as PasswordResetServiceProviderBase;
class PasswordResetServiceProvider extends PasswordResetServiceProviderBase
{
protected function registerPasswordBroker()
{
$this->app->singleton('auth.password', function ($app) {
// reference your new broker
// the rest of the method code is unchanged
return new PasswordBrokerManager($app);
});
$this->app->bind('auth.password.broker', function ($app) {
return $app->make('auth.password')->broker();
});
}
}
接下来,将默认密码重置服务提供商替换为应用程序配置中的自定义服务提供商:
app/config/app.php
<?php
return [
"providers" => [
...
// Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
App\Providers\PasswordResetServiceProvider::class,
...
],
];
最后,在您的用户模型上定义getMobileForPasswordReset() 方法:
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
...
class User extends Authenticatable
{
...
public method getMobileForPasswordReset()
{
return $this->mobile;
}
}