如何在 Laravel 5.8 中扩展或制作自定义 PasswordBroker sendResetLink() 方法?
How to extend or make custom PasswordBroker sendResetLink() method in Laravel 5.8?
目前重置密码背后的逻辑是用户必须提供 valid/registered 电子邮件才能接收密码恢复电子邮件。
在我的例子中,出于安全考虑,我不想验证电子邮件是否已注册,我只想在后端进行检查并告诉用户 "If he has provided registered e-mail, he should get recovery e-mail shortly"。
我为实现这一目标所做的工作是在 vendor\laravel\framework\src\Illuminate\Auth\Passwords\PasswordBroker.php
sendResetLink()
方法中编辑的:
/**
* Send a password reset link to a user.
*
* @param array $credentials
* @return string
*/
public function sendResetLink(array $credentials)
{
// First we will check to see if we found a user at the given credentials and
// if we did not we will redirect back to this current URI with a piece of
// "flash" data in the session to indicate to the developers the errors.
$user = $this->getUser($credentials);
if (is_null($user)) {
return static::INVALID_USER;
}
// Once we have the reset token, we are ready to send the message out to this
// user with a link to reset their password. We will then redirect back to
// the current URI having nothing set in the session to indicate errors.
$user->sendPasswordResetNotification(
$this->tokens->create($user)
);
return static::RESET_LINK_SENT;
}
对此:
/**
* Send a password reset link to a user.
*
* @param array $credentials
* @return string
*/
public function sendResetLink(array $credentials)
{
// First we will check to see if we found a user at the given credentials and
// if we did not we will redirect back to this current URI with a piece of
// "flash" data in the session to indicate to the developers the errors.
$user = $this->getUser($credentials);
// if (is_null($user)) {
// return static::INVALID_USER;
// }
// Once we have the reset token, we are ready to send the message out to this
// user with a link to reset their password. We will then redirect back to
// the current URI having nothing set in the session to indicate errors.
if(!is_null($user)) {
$user->sendPasswordResetNotification(
$this->tokens->create($user)
);
}
return static::RESET_LINK_SENT;
}
这个硬编码选项不是最好的解决方案,因为它会在更新后消失。所以我想知道如何在 [=15] 的项目范围内扩展或实施此更改=] 文件夹 以始终保留此更改?
P.S。我已经尝试过这里提到的解决方案: 但它没有用.. 目录树也不同,我无法理解在哪里放置新的 PasswordBroker.php
文件。
提前致谢!
以下是您需要遵循的步骤。
创建新自定义 PasswordResetsServiceProvider
。我有一个名为 Extensions
的文件夹(命名空间),我将在其中放置此文件:
<?php
namespace App\Extensions\Passwords;
use Illuminate\Auth\Passwords\PasswordResetServiceProvider as BasePasswordResetServiceProvider;
class PasswordResetServiceProvider extends BasePasswordResetServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true;
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerPasswordBroker();
}
/**
* 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();
});
}
}
如您所见,此提供程序扩展了基本密码重置提供程序。唯一改变的是我们从 registerPasswordBroker
方法返回自定义 PasswordBrokerManager
。让我们在同一个命名空间中创建一个自定义 Broker 管理器:
<?php
namespace App\Extensions\Passwords;
use Illuminate\Auth\Passwords\PasswordBrokerManager as BasePasswordBrokerManager;
class PasswordBrokerManager extends BasePasswordBrokerManager
{
/**
* Resolve the given broker.
*
* @param string $name
* @return \Illuminate\Contracts\Auth\PasswordBroker
*
* @throws \InvalidArgumentException
*/
protected function resolve($name)
{
$config = $this->getConfig($name);
if (is_null($config)) {
throw new InvalidArgumentException(
"Password resetter [{$name}] is not defined."
);
}
// The password broker uses a token repository to validate tokens and send user
// password e-mails, as well as validating that password reset process as an
// aggregate service of sorts providing a convenient interface for resets.
return new PasswordBroker(
$this->createTokenRepository($config),
$this->app['auth']->createUserProvider($config['provider'] ?? null)
);
}
}
同样,此 PasswordBrokerManager 扩展了 laravel 的基本管理器。这里唯一的区别是新的 resolve 方法,它 returns 来自同一命名空间的新自定义 PasswordBroker
。所以我们将在同一命名空间中创建一个自定义 PasswordBroker
的最后一个文件:
<?php
namespace App\Extensions\Passwords;
use Illuminate\Auth\Passwords\PasswordBroker as BasePasswordBroker;
class PasswordBroker extends BasePasswordBroker
{
/**
* Send a password reset link to a user.
*
* @param array $credentials
* @return string
*/
public function sendResetLink(array $credentials)
{
// First we will check to see if we found a user at the given credentials and
// if we did not we will redirect back to this current URI with a piece of
// "flash" data in the session to indicate to the developers the errors.
$user = $this->getUser($credentials);
// if (is_null($user)) {
// return static::INVALID_USER;
// }
// Once we have the reset token, we are ready to send the message out to this
// user with a link to reset their password. We will then redirect back to
// the current URI having nothing set in the session to indicate errors.
if(!is_null($user)) {
$user->sendPasswordResetNotification(
$this->tokens->create($user)
);
}
return static::RESET_LINK_SENT;
}
}
如您所见,我们从 Laravel 扩展了默认的 PasswordBroker class 并且只覆盖了我们需要覆盖的方法。
最后一步是简单地用我们的替换 Laravel 默认 PasswordReset 代理。在 config/app.php
文件中,更改注册提供程序的行:
'providers' => [
...
// Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
App\Extensions\Passwords\PasswordResetServiceProvider::class,
...
]
这就是注册自定义密码代理所需的全部内容。希望对您有所帮助。
此处最简单的解决方案是将自定义代码放入 app\Http\Controllers\Auth\ForgotPasswordController
- 这是引入 SendsPasswordResetEmails
特征的控制器。
您的方法覆盖了该特征提供的方法,因此将调用它而不是特征中的方法。您可以使用您的代码覆盖整个 sendResetLinkEmail
方法,无论是否成功,始终 return 相同的响应。
public function sendResetLinkEmail(Request $request)
{
$this->validateEmail($request);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$response = $this->broker()->sendResetLink(
$request->only('email')
);
return back()->with('status', "If you've provided registered e-mail, you should get recovery e-mail shortly.");
}
您可以只覆盖 ForgetPasswordController
class 中的 sendResetLinkFailedResponse
方法。
protected function sendResetLinkFailedResponse(Request $request, $response)
{
return $this->sendResetLinkResponse($request, Password::RESET_LINK_SENT);
}
即使验证失败,我们也会发送成功响应。
目前重置密码背后的逻辑是用户必须提供 valid/registered 电子邮件才能接收密码恢复电子邮件。
在我的例子中,出于安全考虑,我不想验证电子邮件是否已注册,我只想在后端进行检查并告诉用户 "If he has provided registered e-mail, he should get recovery e-mail shortly"。
我为实现这一目标所做的工作是在 vendor\laravel\framework\src\Illuminate\Auth\Passwords\PasswordBroker.php
sendResetLink()
方法中编辑的:
/**
* Send a password reset link to a user.
*
* @param array $credentials
* @return string
*/
public function sendResetLink(array $credentials)
{
// First we will check to see if we found a user at the given credentials and
// if we did not we will redirect back to this current URI with a piece of
// "flash" data in the session to indicate to the developers the errors.
$user = $this->getUser($credentials);
if (is_null($user)) {
return static::INVALID_USER;
}
// Once we have the reset token, we are ready to send the message out to this
// user with a link to reset their password. We will then redirect back to
// the current URI having nothing set in the session to indicate errors.
$user->sendPasswordResetNotification(
$this->tokens->create($user)
);
return static::RESET_LINK_SENT;
}
对此:
/**
* Send a password reset link to a user.
*
* @param array $credentials
* @return string
*/
public function sendResetLink(array $credentials)
{
// First we will check to see if we found a user at the given credentials and
// if we did not we will redirect back to this current URI with a piece of
// "flash" data in the session to indicate to the developers the errors.
$user = $this->getUser($credentials);
// if (is_null($user)) {
// return static::INVALID_USER;
// }
// Once we have the reset token, we are ready to send the message out to this
// user with a link to reset their password. We will then redirect back to
// the current URI having nothing set in the session to indicate errors.
if(!is_null($user)) {
$user->sendPasswordResetNotification(
$this->tokens->create($user)
);
}
return static::RESET_LINK_SENT;
}
这个硬编码选项不是最好的解决方案,因为它会在更新后消失。所以我想知道如何在 [=15] 的项目范围内扩展或实施此更改=] 文件夹 以始终保留此更改?
P.S。我已经尝试过这里提到的解决方案:PasswordBroker.php
文件。
提前致谢!
以下是您需要遵循的步骤。
创建新自定义 PasswordResetsServiceProvider
。我有一个名为 Extensions
的文件夹(命名空间),我将在其中放置此文件:
<?php
namespace App\Extensions\Passwords;
use Illuminate\Auth\Passwords\PasswordResetServiceProvider as BasePasswordResetServiceProvider;
class PasswordResetServiceProvider extends BasePasswordResetServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true;
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerPasswordBroker();
}
/**
* 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();
});
}
}
如您所见,此提供程序扩展了基本密码重置提供程序。唯一改变的是我们从 registerPasswordBroker
方法返回自定义 PasswordBrokerManager
。让我们在同一个命名空间中创建一个自定义 Broker 管理器:
<?php
namespace App\Extensions\Passwords;
use Illuminate\Auth\Passwords\PasswordBrokerManager as BasePasswordBrokerManager;
class PasswordBrokerManager extends BasePasswordBrokerManager
{
/**
* Resolve the given broker.
*
* @param string $name
* @return \Illuminate\Contracts\Auth\PasswordBroker
*
* @throws \InvalidArgumentException
*/
protected function resolve($name)
{
$config = $this->getConfig($name);
if (is_null($config)) {
throw new InvalidArgumentException(
"Password resetter [{$name}] is not defined."
);
}
// The password broker uses a token repository to validate tokens and send user
// password e-mails, as well as validating that password reset process as an
// aggregate service of sorts providing a convenient interface for resets.
return new PasswordBroker(
$this->createTokenRepository($config),
$this->app['auth']->createUserProvider($config['provider'] ?? null)
);
}
}
同样,此 PasswordBrokerManager 扩展了 laravel 的基本管理器。这里唯一的区别是新的 resolve 方法,它 returns 来自同一命名空间的新自定义 PasswordBroker
。所以我们将在同一命名空间中创建一个自定义 PasswordBroker
的最后一个文件:
<?php
namespace App\Extensions\Passwords;
use Illuminate\Auth\Passwords\PasswordBroker as BasePasswordBroker;
class PasswordBroker extends BasePasswordBroker
{
/**
* Send a password reset link to a user.
*
* @param array $credentials
* @return string
*/
public function sendResetLink(array $credentials)
{
// First we will check to see if we found a user at the given credentials and
// if we did not we will redirect back to this current URI with a piece of
// "flash" data in the session to indicate to the developers the errors.
$user = $this->getUser($credentials);
// if (is_null($user)) {
// return static::INVALID_USER;
// }
// Once we have the reset token, we are ready to send the message out to this
// user with a link to reset their password. We will then redirect back to
// the current URI having nothing set in the session to indicate errors.
if(!is_null($user)) {
$user->sendPasswordResetNotification(
$this->tokens->create($user)
);
}
return static::RESET_LINK_SENT;
}
}
如您所见,我们从 Laravel 扩展了默认的 PasswordBroker class 并且只覆盖了我们需要覆盖的方法。
最后一步是简单地用我们的替换 Laravel 默认 PasswordReset 代理。在 config/app.php
文件中,更改注册提供程序的行:
'providers' => [
...
// Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
App\Extensions\Passwords\PasswordResetServiceProvider::class,
...
]
这就是注册自定义密码代理所需的全部内容。希望对您有所帮助。
此处最简单的解决方案是将自定义代码放入 app\Http\Controllers\Auth\ForgotPasswordController
- 这是引入 SendsPasswordResetEmails
特征的控制器。
您的方法覆盖了该特征提供的方法,因此将调用它而不是特征中的方法。您可以使用您的代码覆盖整个 sendResetLinkEmail
方法,无论是否成功,始终 return 相同的响应。
public function sendResetLinkEmail(Request $request)
{
$this->validateEmail($request);
// We will send the password reset link to this user. Once we have attempted
// to send the link, we will examine the response then see the message we
// need to show to the user. Finally, we'll send out a proper response.
$response = $this->broker()->sendResetLink(
$request->only('email')
);
return back()->with('status', "If you've provided registered e-mail, you should get recovery e-mail shortly.");
}
您可以只覆盖 ForgetPasswordController
class 中的 sendResetLinkFailedResponse
方法。
protected function sendResetLinkFailedResponse(Request $request, $response)
{
return $this->sendResetLinkResponse($request, Password::RESET_LINK_SENT);
}
即使验证失败,我们也会发送成功响应。