我在使用Laravel时遇到了一个奇怪的问题。
正常创建用户后,用户第一次可以登录,但此后Auth::attempt
总是失败。我只能通过代码更新用户密码再次登录,当我检查数据库时,所有密码都正确哈希。
$user = new User;
$user->username = Input::get('username');
$user->email = Input::get('email');
$user->password = Input::get('password');
$user->save();
$general = Role::find(3);
$user->roles()->attach($general->id);
登录方法$username = Input::get('username');
$pwd = Input::get('password');
if (!($pwd && $username)) {
return Redirect::intended('user/login')->withMessage('Emtpy username/password')->withInput();
}
if (Auth::attempt(array('username' => $username, 'password' => $pwd))){
return Redirect::intended('user/dashboard');
}
elseif (Auth::attempt(array('email' => $username, 'password' => $pwd))) {
return Redirect::intended('user/dashboard');
}
else {
return Redirect::intended('user/login')->withMessage('Incorrect username/password')->withInput();
}
用户模型
public static function boot()
{
parent::boot();
static::saving(function($data) {
$data->password = Hash::make($data->password);
unset($data->password_confirmation);
return true;
});
}
问题是您使用了错误的事件侦听器。
您错误地连接到save
事件,每次发生用户模型更改时(即在creating
和updating
上)都称为。
这意味着每次用户登录,并做一些操作(更新登录计数,更改他们的名字等)-它会导致模型重新哈希已经哈希的密码,从而使其被破坏。
有两个选项可以解决这个问题。
选项一是将事件更改为仅在creating
事件上工作。但这意味着以后当你需要更新用户密码时,它不会被正确地重新散列,所以选项2更好。
选项2是不使用任何事件,而只使用mutator函数——这是为精确的情况而设计的。
class User extends Eloquent {
public function setPasswordAttribute($value)
{
$this->attributes['password'] = Hash::make($value);
}
}
这样,无论何时何地有人更改用户密码,它都将被散列,但只有在实际需要更改时才会进行散列。
我可以通过重写默认的雄辩保存方法来解决我的问题,并在创建用户时手动创建哈希。下面是代码:
public function save(array $options = array())
{
if (isset($this->password_confirmation))
{
unset($this->password_confirmation);
}
if (isset($this->password))
{
if (Hash::needsRehash($this->password))
{
$this->password = Hash::make($this->password);
}
}
parent::save();
}
然而,我仍然无法找出为什么这种奇怪的经历一次又一次地发生。我仍然有重现错误的代码(即使在2014年7月22日之前安装了Laravel 4.2 ),并且可以将其提供给任何有兴趣调查此问题的人。
我使用的软件包是Zicaco Entrust和Laravel Frozennode
整个方法太复杂了。简单点。
将您的注册方法更改为:
$user = new User;
$user->username = Input::get('username');
$user->email = Input::get('email');
$user->password = Hash::make(Input::get('password'));
$user->save();
$general = Role::find(3);
$user->roles()->attach($general->id);
扔掉你的"引导"方法。
另外(不太相关,但我喜欢这样做),你可以将登录过程更改为:
$username = Input::get('username');
$pwd = Input::get('password');
if (!($pwd && $username)) {
return Redirect::intended('user/login')->withMessage('Emtpy username/password')->withInput();
}
if (Auth::attempt(array('username' => $username, 'password' => $pwd))
|| Auth::attempt(array('email' => $username, 'password' => $pwd))){
return Redirect::intended('user/dashboard');
}
else {
return Redirect::intended('user/login')->withMessage('Incorrect username/password')->withInput();
}
看来你的问题在这里:
if (Auth::attempt(array('username' => $username, 'password' => $pwd))){
***return Redirect::intended('user/dashboard');***
}
elseif (Auth::attempt(array('email' => $username, 'password' => $pwd))) {
return Redirect::intended('user/dashboard');
如果您使用用户名的第一次验证尝试失败,它将在第二次验证尝试块之前返回方法的重定向。这可能不是您面临的全部问题,但它似乎是一段错误的代码。