I noticed that some developers modify PasswordController.php so that the method resetPassword($user, $password) does not bcrypt password. Instead, the password is bcrypted in model User.php.
Here is an example of that: *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);
}
}
As you can see, there is resetPassword($user, $password) method copied from vendor/laravel/framework/src/Illuminate/Foundation/Auth/ ResetPasswords.php. It is modified so that there is no bcrypting password.
Here's how this method originally looked like:
protected function resetPassword($user, $password)
{
$user->password = bcrypt($password);
$user->save();
Auth::guard($this->getGuard())->login($user);
}
(also, as you can see - Auth::guard($this->getGuard())->login($user); is changed to auth()->login($user);)
The idea is to create a mutator in model Users.php in which password will be bcrypted.
So, here is the model User.php with that mutator:
<?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);
}
}
Questions:
1. What would be the reason to do something like that (to create a mutator in Users.php to bcrypt password AND NOT in resetPassword($user, $password) as it is by default)? Why would move bcrypting password from resetPassword($user, $password) to User.php model, is there some practical reason to do such a thing?
2. What is the difference between: auth()->login($user); and Auth::guard($this->getGuard())->login($user); ?
By the way, here is the 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'
]);
});
Another answer to question 1:
You can register a custom UserProvider so that you can override the database part of Laravel's security implementation. I spent a bit of time today implementing authentication against a legacy database, where the passwords are stored as md5 hashes of the supplied password. This was done by registering a custom UserProvider, and from an authentication perspective it works well.
Using bcrypt and then setting the password is an architectural problem in Laravel as this assumes that the custom UserProvider will store bcrypt hashes for passwords. Replacing this hardwired logic with a mutator places the logic in the right place - custom UserProviders can now load and store authentication data however they need. In general it is invasive to dictate how passwords are encrypted, even with the out-of-the-box security implementation.
The problem with the above-mentioned override of PasswordController::resetPassword($user, $password) is that it involves reverse engineering of internal logic - it wastes time hunting down and replacing the errant behaviour, and the workaround can stop working at any time that the internal logic changes.
FYI there is another less invasive hack to get around this. Before setting the new password, UserProvider::retrieveByCredentials(array $credentials) is called to validate and load the user for whom the password is being reset. The $credentials array contains the new plaintext password only on password reset, so you can cache the password as an attribute during the password reset flow. On UserProvider::save(), ignore the bcrypt hash and use the cached password instead. This does mean that you have to have an AuthUser that is separate from the actual user model though.