'登录帐号', 'password' => '登录密码', 'verifyCode' => '验证码', ]; } /** * @inheritdoc */ public function rules() { return [ // username and password are both required [['adminName', 'password', 'verifyCode'], 'required'], // rememberMe must be a boolean value ['verifyCode', 'captcha', 'captchaAction'=>'/v1/site/captcha'], // password is validated by validatePassword() //['password', 'validatePassword'], ]; } /** * Validates the password. * This method serves as the inline validation for password. * * @param string $attribute the attribute currently being validated * @param array $params the additional name-value pairs given in the rule */ public function validatePassword($attribute, $params) { if (!$this->hasErrors()) { $this->getUser(); if(!$this->_user){ $this->addError($attribute, '会员不存在'); return false; } if (!$this->_user->validatePassword($this->password)) { $this->addError($attribute, '用户名或者密码错误'); return false; } //验证IP $bindIp = trim($this->_user['BIND_IP']); if(!empty($bindIp) && !(new LoginIpChecker(Yii::$app->request->getUserIP(), $bindIp))->validate()){ $this->addError($attribute, '登录IP与此账号绑定的IP不符'); return false; } return true; } return false; } /** * 更新失败次数 * @param $transaction * @param $returnResult * @throws \Exception */ private function _updateFailTimes($transaction,$returnResult){ Admin::updateAllCounters([ 'FAIL_NUMS' => 1, ], 'ADMIN_NAME=:ADMIN_NAME', ['ADMIN_NAME' => $this->adminName]); $transaction->commit(); if(isset($this->_user)){ AdminLoginLogger::fail($this->_user,$returnResult, $this->password); } // 失败写入缓存锁 Yii::$app->redis->incr('FAIL_NUMS:' . $this->adminName); } /** * 更新成功次数 */ private function _updateSuccessTimes(){ Admin::updateAllCounters([ 'LOGIN_NUMS' => 1, ], 'ADMIN_NAME=:ADMIN_NAME', ['ADMIN_NAME' => $this->adminName]); } /** * 登录 * @return array|bool * @throws \yii\base\Exception * @throws \yii\db\Exception */ public function login(){ if(!$this->validate()){ return false; } $transaction = \Yii::$app->db->beginTransaction(); try{ $this->getUser(); if(!$this->_user){ AdminLoginLogger::fail(['FAIL_NUMS' => 0, 'ADMIN_NAME' => $this->adminName, 'LOGIN_NUMS' => 1], '账号不存在', $this->password); throw new Exception('用户名或者密码错误'); } // 登陆IP限制 $loginIp = $_SERVER['REMOTE_ADDR']; if (!Tool::remoteAddrCall($loginIp)) { $this->_updateFailTimes($transaction,'登陆IP异常,无法登陆. ' . $loginIp); throw new Exception('用户名或者密码错误'); } // 失败次数到达上限次数 $loginFailNums = Yii::$app->redis->get('FAIL_NUMS:' . $this->adminName) ?? 0; if ($loginFailNums >= 3) { $this->_updateFailTimes($transaction,'账号登陆失败次数过多,无法登录. ' . $loginFailNums); throw new Exception('用户名或者密码错误'); } if(!$this->_user['IS_ENABLE']){ $this->_updateFailTimes($transaction,'账号已经被锁定,无法登录'); throw new Exception('用户名或者密码错误'); } if (!$this->_user->validatePassword($this->password)) { $this->_updateFailTimes($transaction,'用户名或者密码错误'); throw new Exception('用户名或者密码错误'); } //验证IP $bindIp = trim($this->_user['BIND_IP']); if(!empty($bindIp) && !(new LoginIpChecker(Yii::$app->request->getUserIP(), $bindIp))->validate()){ $this->_updateFailTimes($transaction,'登录IP与此账号绑定的IP不符'); throw new Exception('用户名或者密码错误'); } //需要修改密码 if($this->_user['IS_MODIFY_PASSWORD'] == 1){ throw new Exception(self::ERROR_IS_MODIFY_PASSWORD); } $this->_updateSuccessTimes(); $transaction->commit(); AdminLoginLogger::success($this->_user, $this->password); // 把用户的登录时间存在操作时间里 Yii::$app->tokenRedis->hset('admin:timeOut', $this->_user->getId(), time()); return Yii::$app->user->loginWithUAndP($this->_user); }catch(\Exception $e){ $transaction->rollBack(); $this->setError($e->getMessage()); //AdminLoginLogger::fail($this->_user, $e->getMessage()); return false; } } /** * Finds user by [[username]] * * @return User|null */ public function getUser() { if ($this->_user === null) { $this->_user = User::findByUsername(strtolower($this->adminName)); } return $this->_user; } }