Laravel 5:密码重置 - 将bcrypt密码移动到User.php模型中?

3
我注意到有些开发者修改了 PasswordController.php 文件,使得方法 resetPassword($user, $password) 不再使用 bcrypt 加密密码。相反,密码是在 User.php 模型中进行 bcrypt 加密的。
以下是一个示例:*app/Http/Controllers/Auth/PasswordController.php:
<?php

namespace SundaySlim\Http\Controllers\Auth;

use SundaySlim\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;

class PasswordController extends Controller
{

   use ResetsPasswords;

  public function __construct()
  {
      $this->redirectTo = route('backend.dashboard');
      $this->middleware('guest');
  }

  protected function resetPassword($user, $password)
  {
     $user->password = $password;
     $user->save();
     auth()->login($user);
  }
}

您可以看到,这里有一个resetPassword($user, $password)方法,它是从vendor/laravel/framework/src/Illuminate/Foundation/Auth/ResetPasswords.php中复制的。它被修改了,以便不再使用bcrypt加密密码。

以下是该方法原始代码:

protected function resetPassword($user, $password)
{
    $user->password = bcrypt($password);

    $user->save();

    Auth::guard($this->getGuard())->login($user);
}

同时,可以看到 - Auth::guard($this->getGuard())->login($user); 已更改为 auth()->login($user);

主要思路是在 Users.php 模型中创建一个修改器,将密码加密为bcrypt码。

因此,以下是带有该修改器的模型User.php

<?php

namespace SundaySlim;

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    protected $fillable = [
        'name', 'email', 'password',
    ];

    protected $hidden = [
        'password', 'remember_token',
    ];

    public function setPasswordAttribute($value)
    {
        $this->attributes['password'] = bcrypt($value);
    }
}

问题:

1. 为什么要在 Users.php 中创建一个改变器来bcrypt密码,而不是像默认情况下那样在 resetPassword($user,$password) 中进行?将bcrypt密码从 resetPassword($user,$password) 移动到User.php模型中的实际原因是什么?

2. auth()->login($user); Auth::guard($this->getGuard())->login($user);之间有什么区别?

顺便说一下,这是 routes.php 的内容:

Route::group(['middleware' => ['web']], function () {

    Route::get('backend/dashboard', [
        'uses'=>'Backend\DashboardController@index',
        'as'=>'backend.dashboard'
    ]);

    Route::controller('auth', 'Auth\AuthController', [
        'getLogin' => 'auth.login',
        'getLogout' => 'auth.logout'
    ]);

    Route::controller('auth/password', 'Auth\PasswordController', [
        'getEmail' => 'auth.password.email',
        'getReset' => 'auth.password.reset' 
    ]);
});

3
回答问题1:为密码设置一个修改器(mutator)来加密它,可以防止开发人员绕过控制器方法而未能对密码进行加密 - 他们不能只在模型上设置明文密码并保存。 - Kryten
3
假设我是一位开发者,编写了以下代码:$user->password = 'something'; $user->save();。如果存在mutator(属性修改器),那么在保存前用户模型中的密码将被加密。如果不存在mutator,那么该密码将以明文形式保存至数据库。 - Kryten
@Kryten 哦,我现在理解了。我想知道为什么 Laravel 的 User.php 模型默认没有这样的 mutator,但我们需要修改 PasswordController.php(例如,从 resetPassword($user, $password) 中删除 bcrypt 并在模型中创建 mutator... - PeraMika
1个回答

1

对于问题1的另一个答案:

您可以注册自定义UserProvider,以便覆盖Laravel安全实现的数据库部分。我今天花了一些时间实现与传统数据库的身份验证,其中密码存储为提供的密码的md5哈希值。这是通过注册自定义UserProvider来完成的,从身份验证的角度来看,它运行良好。

在Laravel中使用bcrypt,然后设置密码是一个架构问题,因为这假定自定义UserProvider将为密码存储bcrypt哈希。使用变异器替换这个硬编码逻辑可以将逻辑放置在正确的位置 - 自定义UserProviders现在可以根据需要加载和存储身份验证数据。总的来说,即使使用开箱即用的安全实现,强制规定密码加密方式也具有侵入性。

上述PasswordController :: resetPassword($ user,$ password)覆盖的问题在于它涉及内部逻辑的反向工程 - 它浪费时间寻找并替换错误行为,并且解决方法随时可能停止工作,当内部逻辑发生变化时。

提供一种不那么侵入性的方法来解决这个问题。在设置新密码之前,会调用UserProvider::retrieveByCredentials(array $credentials)来验证并加载要重置密码的用户。$credentials数组仅在密码重置时包含新的明文密码,因此您可以在密码重置流程中将密码缓存为属性。在UserProvider::save()中,忽略bcrypt哈希并使用缓存的密码。但这意味着您必须拥有一个与实际用户模型分开的AuthUser。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接