config = array_merge($this->config, $config); } $this->options = array_merge($this->config, $options); } public static function instance($options = []) { if (is_null(self::$instance)) { self::$instance = new static($options); } return self::$instance; } /** * 兼容调用application模型的属性 * * @param string $name * @return mixed */ public function __get($name) { return $this->_application ? $this->_application->$name : null; } /** * 兼容调用application模型的属性 */ public function __isset($name) { return isset($this->_application) ? isset($this->_application->$name) : false; } /** * 根据Token初始化验货员身份 * @param string $token * @return bool */ public function init($token) { if ($this->_logined) { return true; } if ($this->_error) { return false; } if (!$token) { return false; } $application = InspectionApplication::where([ 'token' => $token, 'audit_status' => 2, 'status' => 1 ])->where('token_expire_time', '>', time())->find(); if (!$application) { $this->setError('验货员未登录或登录已过期'); return false; } $user = User::get($application->user_id); if (!$user) { $this->setError('用户不存在'); return false; } if ($user->status != 1) { $this->setError('用户已被禁用'); return false; } $this->_application = $application; $this->_user = $user; $this->_logined = true; $this->_token = $token; //初始化成功的事件 Hook::listen("inspection_init_successed", $this->_application); return true; } /** * 验货员登录 * @param string $phone 手机号 * @param string $password 密码(实际项目中可能需要验证码等) * @return bool */ public function login($phone, $password = '') { $application = InspectionApplication::where([ 'phone' => $phone, 'audit_status' => 2, 'status' => 1 ])->find(); if (!$application) { $this->setError('验货员不存在或未通过审核'); return false; } $user = User::get($application->user_id); if (!$user) { $this->setError('关联用户不存在'); return false; } if ($user->status != 1) { $this->setError('用户已被禁用'); return false; } // 检查登录失败次数 if ($application->login_failure >= 10 && time() - $application->login_failure_time < 86400) { $this->setError('登录失败次数过多,请24小时后重试'); return false; } // 验证密码 if ($password && $application->password != $this->getEncryptPassword($password, $application->salt)) { $application->save(['login_failure' => $application->login_failure + 1, 'login_failure_time' => time()]); $this->setError('密码错误'); return false; } //直接登录验货员 return $this->direct($application->user_id); } /** * 直接登录验货员 * @param int $user_id * @return bool */ public function direct($id) { $application = InspectionApplication::where([ 'id' => $id, 'audit_status' => 2, 'status' => 1 ])->find(); if (!$application) { $this->setError('验货员未通过审核'); return false; } $user = User::get($application->user_id); if (!$user) { $this->setError('关联用户不存在'); return false; } Db::startTrans(); try { $ip = request()->ip(); $time = time(); $token = Random::uuid(); $expire = $time + $this->keeptime; //判断连续登录和最大连续登录 if ($application->login_time < \fast\Date::unixtime('day')) { $application->successions = $application->login_time < \fast\Date::unixtime('day', -1) ? 1 : $application->successions + 1; $application->max_successions = max($application->successions, $application->max_successions); } $application->prev_time = $application->login_time; //记录本次登录的IP和时间 $application->login_ip = $ip; $application->login_time = $time; //重置登录失败次数 $application->login_failure = 0; //设置token $application->token = $token; $application->token_expire_time = $expire; $application->save(); $this->_application = $application; $this->_user = $user; $this->_logined = true; $this->_token = $token; //登录成功的事件 Hook::listen("inspection_login_successed", $this->_application); Db::commit(); } catch (Exception $e) { Db::rollback(); $this->setError($e->getMessage()); return false; } return true; } /** * 退出登录 * @return bool */ public function logout() { if (!$this->_logined) { $this->setError('未登录'); return false; } Db::startTrans(); try { $this->_application->token = null; $this->_application->token_expire_time = null; $this->_application->save(); $this->_logined = false; $this->_token = ''; //退出成功的事件 Hook::listen("inspection_logout_successed", $this->_application); Db::commit(); } catch (Exception $e) { Db::rollback(); $this->setError($e->getMessage()); return false; } return true; } /** * 修改密码 * @param string $newpassword 新密码 * @param string $oldpassword 旧密码 * @param bool $ignoreoldpassword 忽略旧密码 * @return boolean */ public function changepwd($newpassword, $oldpassword = '', $ignoreoldpassword = false) { if (!$this->_logined) { $this->setError('您尚未登录'); return false; } //判断旧密码是否正确 if ($this->_application->password == $this->getEncryptPassword($oldpassword, $this->_application->salt) || $ignoreoldpassword) { Db::startTrans(); try { $salt = Random::alnum(); $newpassword = $this->getEncryptPassword($newpassword, $salt); // 更新验货员申请表的密码和salt $this->_application->password = $newpassword; $this->_application->salt = $salt; $this->_application->login_failure = 0; // 清除当前token,强制重新登录 $this->_application->token = null; $this->_application->token_expire_time = null; $this->_application->save(); //修改密码成功的事件 Hook::listen("inspection_changepwd_successed", $this->_application); Db::commit(); } catch (Exception $e) { Db::rollback(); $this->setError($e->getMessage()); return false; } return true; } else { $this->setError('旧密码错误'); return false; } } /** * 判断是否已登录 * @return bool */ public function isLogin() { return $this->_logined; } /** * 获取当前Token * @return string */ public function getToken() { return $this->_token; } /** * 获取验货员申请信息 * @return InspectionApplication|null */ public function getApplication() { return $this->_application; } /** * 获取验货员用户信息 * @return User|null */ public function getUser() { return $this->_user; } /** * 获取验货员基本信息 */ public function getInspectorInfo() { if (!$this->_application) { return null; } $data = $this->_application->toArray(); $allowFields = $this->getAllowFields(); $inspectorInfo = array_intersect_key($data, array_flip($allowFields)); // 添加token信息 $inspectorInfo['token'] = $this->_token; $inspectorInfo['token_expire_time'] = $this->_application->token_expire_time; return $inspectorInfo; } /** * 获取供应商ID * @return int */ public function getSupplierId() { return $this->_application ? $this->_application->supplier_id : 0; } /** * 获取当前请求的URI * @return string */ public function getRequestUri() { return $this->requestUri; } /** * 设置当前请求的URI * @param string $uri */ public function setRequestUri($uri) { $this->requestUri = $uri; } /** * 获取允许输出的字段 * @return array */ public function getAllowFields() { return $this->allowFields; } /** * 设置允许输出的字段 * @param array $fields */ public function setAllowFields($fields) { $this->allowFields = $fields; } /** * 检测当前控制器和方法是否匹配传递的数组 * * @param array $arr 需要验证权限的数组 * @return boolean */ public function match($arr = []) { $request = Request::instance(); $arr = is_array($arr) ? $arr : explode(',', $arr); if (!$arr) { return false; } $arr = array_map('strtolower', $arr); // 是否存在 if (in_array(strtolower($request->action()), $arr) || in_array('*', $arr)) { return true; } // 没找到匹配 return false; } /** * 设置会话有效时间 * @param int $keeptime 默认为永久 */ public function keeptime($keeptime = 0) { $this->keeptime = $keeptime; } /** * 设置初始密码 * @param string $password 密码 * @return boolean */ public function setPassword($password) { if (!$this->_application) { $this->setError('验货员信息不存在'); return false; } try { $salt = Random::alnum(); $encryptPassword = $this->getEncryptPassword($password, $salt); $this->_application->password = $encryptPassword; $this->_application->salt = $salt; $this->_application->save(); return true; } catch (Exception $e) { $this->setError($e->getMessage()); return false; } } /** * 更新头像 * @param string $avatar 头像路径 * @return boolean */ public function updateAvatar($avatar) { if (!$this->_logined) { $this->setError('您尚未登录'); return false; } try { $this->_application->avatar = $avatar; $this->_application->save(); //更新头像成功的事件 Hook::listen("inspection_update_avatar_successed", $this->_application); return true; } catch (Exception $e) { $this->setError($e->getMessage()); return false; } } /** * 获取头像完整URL * @return string */ public function getAvatar() { if (!$this->_application || !$this->_application->avatar) { return ''; } return cdnurl($this->_application->avatar, true); } /** * 获取密码加密后的字符串 * @param string $password 密码 * @param string $salt 密码盐 * @return string */ public function getEncryptPassword($password, $salt = '') { return md5(md5($password) . $salt); } /** * 设置错误信息 * @param string $error * @return $this */ public function setError($error) { $this->_error = $error; return $this; } /** * 获取错误信息 * @return string */ public function getError() { return $this->_error ? __($this->_error) : ''; } }