问题
By default Laravel 5.5's password reset system works on email, but I need to add support for a mobile number (verify by OTP and generate a token and redirect to password reset page). I am doing all this part and I have created a mobile column on password_resets table.
But the problem is \Illuminate\Auth\Passwords\DatabaseTokenRepository
&& \Illuminate\Auth\Passwords\TokenRepositoryInterface
ON exist
method and it doesn't seem configurable.
public function exists(CanResetPasswordContract $user, $token)
{
$record = (array) $this->getTable()->where(
'email', $user->getEmailForPasswordReset()
)->first();
return $record &&
! $this->tokenExpired($record['created_at']) &&
$this->hasher->check($token, $record['token']);
}
I need to override that method. There's so much inheritance going on. What classes do I need to extend and how to override that method.
回答1:
If you want to override behaviour of \Illuminate\Auth\Passwords\DatabaseTokenRepository
methods, you will have to override every method that references "email" column. Create these files:
/App/Auth/DatabaseTokenRepository.php
<?php
namespace App\Auth;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Auth\Passwords\DatabaseTokenRepository as DatabaseTokenRepositoryBase;
class DatabaseTokenRepository extends DatabaseTokenRepositoryBase
{
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)
{
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']);
}
}
Now you will need to use this custom token repository instead of the default one. So you have to override another class.
/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 new DatabaseTokenRepository(
$this->app['db']->connection($connection),
$this->app['hash'],
$config['table'],
$key,
$config['expire']
);
}
}
Now you have created a custom broker to use your custom repository. You need a new service provider to make use of it.
/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) {
return new PasswordBrokerManager($app);
});
$this->app->bind('auth.password.broker', function ($app) {
return $app->make('auth.password')->broker();
});
}
}
Then just replace default password reset service provider with the custom one in your application config.
来源:https://stackoverflow.com/questions/58888554/password-reset-in-laravel-5-5-by-email-or-mobile