'登录帐号', 'password' => '登录密码', 'verifyCode' => '验证码', ]; } /** * @inheritdoc */ public function rules() { return [ // username and password are both required [['adminName', 'password', 'verifyCode', 'code'], '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); } // 失败写入缓存锁 Yii::$app->redis->incrby('FAIL_NUMS:' . $this->adminName, 1); } /** * 更新成功次数 */ private function _updateSuccessTimes(){ Admin::updateAllCounters([ 'LOGIN_NUMS' => 1, ], 'ADMIN_NAME=:ADMIN_NAME', ['ADMIN_NAME' => $this->adminName]); // 失败写入缓存锁 Yii::$app->redis->delete('FAIL_NUMS:' . $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){ throw new Exception('账号不存在'); } // 失败次数到达上限次数 $loginFailNums = Yii::$app->redis->get('FAIL_NUMS:' . $this->adminName) ?? 0; LoggerTool::info('FAIL_NUMS:' . $this->adminName . ': ' . $loginFailNums); if ($loginFailNums >= 3) { $this->_updateFailTimes($transaction, '用户名或者密码错误1'); throw new Exception('用户名或者密码错误1'); } // 校验邮箱验证码 // $codeObj = EmailLog::find() // ->where('ADMIN_ID=:ADMIN_ID AND EMAIL=:EMAIL', // [ // ':ADMIN_ID' => $this->_user['ID'], // ':EMAIL' => $this->_user['EMAIL'], // ]) // ->orderBy('CREATED_AT DESC') // ->one() // ->toArray(); // if (!$codeObj || !$codeObj['CODE'] || $codeObj['CODE'] != $this->code) { // throw new Exception('邮箱验证码不正确,无法登录'); // } // if ($codeObj['CREATED_AT'] + 5 * 60 < time()) { // 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); // 把用户的登录时间存在操作时间里 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; } }