【问题标题】:Password resetting in laravel when email address is not unique当电子邮件地址不唯一时,laravel中的密码重置
【发布时间】:2018-09-10 10:14:13
【问题描述】:

这听起来像是一种反模式或弱系统设计,但我的应用程序的客户端要求可以有多个用户使用相同的电子邮件地址。

所以我在 users 表中添加了另一个名为 username 的唯一列,并从 email 列中删除了 ->unique() 约束。

注册、登录正常,但在密码重置过程中出现问题。

考虑场景:

用户名 - johndoe,电子邮件 - john@example.com

用户名 - janedoe,电子邮件 - john@example.com

用户名 - jimmydoe,电子邮件 - john@example.com

如果其中任何人请求密码重置链接,他们必须使用 johndoe@example.com 作为他们的电子邮件。那么当他们点击邮件中的重置链接时,哪个用户的密码实际上会被重置?原来,第一个用户,在这种情况下,是 johndoe。即使请求是由 janedoe 或 jimmydoe 提出的。

那么如何重置单个用户名而不是电子邮件的密码?我应该在 ForgotPasswordController 和/或 ResetPasswordController 控制器中进行哪些更改来解决这个问题?或者,我是否必须在核心框架中进行更改?如果是这样,在哪里以及如何?

【问题讨论】:

  • 这是什么 Laravel 版本?你使用股票密码重置流程吗?
  • 当我想到你的问题时,我越来越想知道,你住在世界上哪个地方人们共享电子邮件帐户的地方。可以通过访问某人的电子邮件帐户来实现各种身份盗用。
  • @Kyslik 是股票密码重置流程。通过添加用户名唯一列,我所做的唯一更改是在用户表中。要回答您的下一个问题,我知道这很奇怪 :D 但仍有一个问题:尽管这些帐户似乎属于不同的用户,但实际上并非如此。所有三个帐户都将由拥有该电子邮件的同一个人访问:-|所以,是的,电子邮件帐户没有与他人共享。
  • 你有桌子password_resets吗?检查它,你会看到它只使用“电子邮件”字段。除此之外,请检查Illuminate\Auth\Passwords\PasswordResetServiceProvider 以了解有关密码流的见解。
  • 您可以修改忘记密码模块,他们可以输入用户名而不是电子邮件ID来启动忘记密码程序

标签: laravel authentication


【解决方案1】:

这听起来像是一种反模式或弱系统设计,但我的应用程序的客户端要求可以有多个用户使用相同的电子邮件地址。

然后您需要重写此功能并询问用户一些更独特的信息,无论它是什么。 Laravel 提供的密码重置期望电子邮件是唯一的,并且在您当前的设计中它不会起作用。这里没有魔法。您不能使用非唯一数据来消除用户的歧义。

【讨论】:

  • username 是独一无二的。这能在某种程度上有所帮助吗?
  • 因为他们在重置链接中都有相同的电子邮件地址,所以请询问女巫用户。我想无论如何这将是一个拥有多个帐户的人。没有其他理由拥有相同的电子邮件。每次遇到问题时应用相同的解决方案。
  • 当然,如果用户名是唯一的,则要求提供该用户名而不是电子邮件。稍作调整,您就可以开始了。我仍然认为允许多个帐户使用相同的电子邮件地址是没有意义的
【解决方案2】:

在 Laravel 5.3 中测试 [此答案修改了一些核心文件(如果有能力,您可以覆盖它),这不是一个干净的解决方案。]

  1. 密码忘记表单上询问用户唯一的username 值而不是email
  2. 覆盖ForgotPasswordController.php 中的sendResetLinkEmail() 方法,如下所示。 【原文写于SendsPasswordResetEmails.php】。

    public function sendResetLinkEmail(Request $request)
    {
        $this->validateEmail($request);
    
        $response = $this->broker()->sendResetLink(
            $request->only('username')
        );
    
        return $response == Password::RESET_LINK_SENT
                    ? $this->sendResetLinkResponse($response)
                    : $this->sendResetLinkFailedResponse($request, $response);
    }
    
  3. 您还需要覆盖 validateEmail() 方法。

    protected function validateEmail(Request $request)
    {
        $this->validate($request, ['username' => 'required']);
    }
    
  4. 密码重置表单上添加username 字段而不是email

  5. ResetPasswordController.php 中覆盖rules() 以克服电子邮件字段更改。

     protected function rules()
        {
            return [
                'token' => 'required',
                'username' => 'required',
                'password' => 'required|confirmed|min:6',
            ];
        }
    
  6. 同时覆盖ResetPasswordController.php中的credentials()

    protected function credentials(Request $request)
        {
            return $request->only(
                'username', 'password', 'password_confirmation', 'token'
            );
        }
    
  7. 更新或覆盖Illuminate\Auth\Passwords\CanResetPassword.php中的getEmailForPasswordReset()方法如下。

    public function getEmailForPasswordReset()
        {
            return $this->username;
        }
    

Laravel 使用键值对来查找用户并发送电子邮件。如果您传递'username => 'xyz',它将在username 字段中查找值为'xyz' 的第一条记录。

注意:用户表中的唯一列应为usernameIlluminate\Auth\Passwords\CanResetPassword.php 是一个 trait,我无法覆盖 getEmailForPasswordReset 方法,所以我只是修改了核心文件本身。

【讨论】:

  • 在哪里覆盖getEmailForPasswordReset() 方法?
  • CanResetPassword 是一个接口。不能简单地在接口中定义方法。
  • 没关系。有两个 CanResetPassword 文件。找到了第二个。并更新了方法。有用。非常感谢。
  • Illuminate\Auth\Passwords\CanResetPassword.php 是一个特征,我无法覆盖 getEmailForPasswordReset 方法,所以我只是修改了核心文件本身。如果您能够或知道,那么您可以覆盖它。 @Eisenheim 很高兴知道它有帮助。
  • @iamab.in 你有没有解决方法来覆盖'Illuminate\Auth\Passwords\CanResetPassword.php'?
【解决方案3】:

您需要为此重新设计一些东西,但我觉得用户体验更好。为每个用户生成一个唯一的密钥(用于数据隐藏)。有一个用于创建唯一键的辅助方法。

然后,当发送电子邮件时,将按钮链接到使用此键的路由。

然后,修改或创建指向重置密码控制器的路由。然后,您将知道它指的是哪个用户。

无需用户输入密码,因为您已经知道密码是谁。

【讨论】:

    猜你喜欢
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    • 2021-11-07
    • 2011-07-15
    • 2019-08-12
    • 2014-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多