Auth::logoutOtherDevices 导致密码错误问题

注:经 [@ALMAS](https://learnku.com/users/7036) 提醒,发现user模型中有定义一个修改器,用于密码处理,问题出在该处,并非laravel 问题。特此纠正,感谢 [@ALMAS](https://learnku.com/users/7036) 的提醒。
代码如下:

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

以上纠正于:2019年7月16日 20:32分!

最近做开发的时候,要求实现单设备登录功能,看了下文档,发现 Auth::logoutOtherDevices($password) 正好满足条件。于是兴冲冲的使用了该方法。结果悲剧了, 账号登录后,Auth::logoutOtherDevices 处理完,再想登录的时候,报密码错误。找问题发现使用 Auth::logoutOtherDevices 后,数据库中的密码变了,用 password_verify 去验证数据库中改变后的密码,死活验证不通过。 好嘛,只能跟踪源码找问题了。

     /**
     * Invalidate other sessions for the current user.
     *
     * The application must be using the AuthenticateSession middleware.
     *
     * @param  string  $password
     * @param  string  $attribute
     * @return bool|null
     */
    public function logoutOtherDevices($password, $attribute = 'password')
    {
        if (! $this->user()) {
            return;
        }

        $result = tap($this->user()->forceFill([
          **$attribute => Hash::make($password),** 
        ]))->save();

        if ($this->recaller() ||
            $this->getCookieJar()->hasQueued($this->getRecallerName())) {
            $this->queueRecallerCookie($this->user());
        }

        $this->fireOtherDeviceLogoutEvent($this->user());

        return $result;
    }

在该方法中,发现密码是Hash::make加密后存储。刚开始以为是这里加密方式问题,后来经测试发现不是。真正的原因是密码被加密了两次,$attribute => Hash::make($password) 加密了一次,在入库的时候又做了一次hash,最终导致密码验证不通过。找到问题就简单了,直接改成如下代码,问题解决。

        $result = tap($this->user()->forceFill([
            **$attribute => $password,**
        ]))->save();

初次发文,请多关照!

longren610
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 9

Laravel多少版本有这个功能?

3个月前 评论
longren610 (楼主) 3个月前
ALMAS

话说入库时怎么会再hash一次?是不是自己写了修改器?

3个月前 评论
longren610 (楼主) 3个月前
_杭城浪子 3个月前
ALMAS (作者) 3个月前
longren610 (楼主) 3个月前
hxd

直接改源码有点不妥吧,可以复写这个方法吗?

3个月前 评论
longren610 (楼主) 3个月前
hxd (作者) 3个月前
longren610 (楼主) 3个月前
hxd (作者) 3个月前
Epona

此方法要求用户提供其当前密码,你的应用程序应通过输入表单接受该密码:

应该把未加密的密码传进去吧

3个月前 评论
longren610 (楼主) 3个月前

**这是什么语法

[
          **$attribute => Hash::make($password),** 
        ]
3个月前 评论
longren610

@lovecn 前后的**号,只是想做一个提示,不是语法。。。 :joy:

3个月前 评论

@longren610 大佬,这个forceFill是个静态方法吗?没找到源码在哪里啊

2个月前 评论
longren610

@nullable 我也只是一只刚接触laravel不久的菜鸟 :joy: 不是大佬啦。如果是laravel5.8的话,这个forceFill 在 vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php 里面,第347行

1个月前 评论
nullable 1个月前

我用的是自带的Auth,只要在LoginController里重写authenticated方法就可以了

    protected function authenticated(Request $request, $user)
    {
        $this->guard()->logoutOtherDevices($request->password);
    }

然后我又碰到了一个问题:在使用

Auth::loginUsingId(1,  $remember  =  false);  //登录指定用户 ID 的用户到应用上

登录时,怎么退出其它设备的登录状态?

1个月前 评论
longren610 (楼主) 1个月前
iscxy (作者) 1个月前
longren610 (楼主) 1个月前
iscxy (作者) 1个月前

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!