| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580 |
- <?php
- namespace app\common\library;
- use app\common\model\User;
- use app\common\model\UserThird;
- use fast\Random;
- use fast\ucenter\client\Client;
- use think\Cookie;
- use think\Db;
- use think\Exception;
- use think\Validate;
- /**
- * Auth类
- */
- class Auth
- {
- const ERR_ACCOUNT_IS_INCORRECT = 'Account is incorrect';
- const ERR_ACCOUNT_NOT_EXIST = 'Account not exist';
- const ERR_USERNAME_IS_INCORRECT = 'Username is incorrect';
- const ERR_EMAIL_IS_INCORRECT = 'Email is incorrect';
- const ERR_PASSWORD_IS_INCORRECT = 'Password is incorrect';
- const ERR_USERNAME_OR_PASSWORD_IS_INCORRECT = 'Username or password is incorrect';
- const ERR_USERNAME_ALREADY_EXIST = 'Username already exist';
- const ERR_EMAIL_ALREADY_EXIST = 'Email already exist';
- const ERR_MOBILE_ALREADY_EXIST = 'Mobile already exist';
- const ERR_ACCOUNT_IS_LOCKED = 'Account is locked';
- const ERR_USERNAME_OR_PASSWORD_IS_MODIFIED = 'Username or password is modified';
- const ERR_YOU_ARE_NOT_LOGGED_IN = 'You are not logged in';
- const ERR_ACCOUNT_ALREADY_LOGGED_IN_AT_ANOTHER_PLACE = 'Account already logged in at another';
- protected static $instance = null;
- private $_error = '';
- private $_logined = FALSE;
- private $user = NULL;
- private $keeptime = 0;
- private $requestUri = '';
- public function __construct()
- {
- $this->user = new User;
- }
- /**
- * 初始化
- * @param array $options 参数
- * @return Auth
- */
- public static function instance($options = [])
- {
- if (is_null(self::$instance))
- {
- self::$instance = new static($options);
- }
- return self::$instance;
- }
- public function __get($name)
- {
- return $this->check() ? $this->user->$name : NULL;
- }
- public function __call($name, $arguments)
- {
- return call_user_func_array([$this->user, $name], $arguments);
- }
- /**
- * 注册用户
- *
- * @param string $username 用户名
- * @param string $password 密码
- * @param string $email 邮箱
- * @param string $mobile 手机号
- * @param string $extend 扩展参数
- * @return boolean
- */
- public function register($username, $password, $email = '', $mobile = '', $extend = [], $keeptime = 0, $sync = TRUE)
- {
- $rule = [
- 'username' => 'require|length:6,30',
- 'password' => 'require|length:6,30',
- 'email' => 'email',
- 'mobile' => 'regex:/^1\d{10}$/',
- ];
- $msg = [
- 'username.require' => __('Username can not be empty'),
- 'username.length' => __('Username must be 6 to 30 characters'),
- 'password.require' => __('Password can not be empty'),
- 'password.length' => __('Password must be 6 to 30 characters'),
- 'email' => __('Email is incorrect'),
- 'mobile' => __('Mobile is incorrect'),
- ];
- $data = [
- 'username' => $username,
- 'password' => $password,
- 'email' => $email,
- 'mobile' => $mobile,
- ];
- $validate = new Validate($rule, $msg);
- $result = $validate->check($data);
- if (!$result)
- {
- $this->setError($validate->getError());
- return FALSE;
- }
- // 检测用户名或邮箱、手机号是否存在
- if (User::getByUsername($username))
- {
- $this->setError(__('Username already exist'));
- return FALSE;
- }
- if ($email && User::getByEmail($email))
- {
- $this->setError(__('Email already exist'));
- return FALSE;
- }
- if ($mobile && User::getByMobile($mobile))
- {
- $this->setError(__('Mobile already exist'));
- return FALSE;
- }
- $ip = request()->ip();
- $time = time();
- $params = array_merge($data, [
- 'nickname' => $username,
- 'salt' => Random::alnum(),
- 'jointime' => $time,
- 'joinip' => $ip,
- 'logintime' => $time,
- 'loginip' => $ip,
- 'prevtime' => $time,
- 'status' => 'normal'
- ]);
- $params['password'] = $this->getEncryptPassword($password, $params['salt']);
- $params = array_merge($params, $extend);
- ////////////////同步到Ucenter////////////////
- if (defined('UC_STATUS') && UC_STATUS && $sync)
- {
- $uc = new Client();
- $user_id = $uc->uc_user_register($username, $password, $email);
- // 如果小于0则说明发生错误
- if ($user_id <= 0)
- {
- $this->setError($user_id > -4 ? self::ERR_USERNAME_IS_INCORRECT : self::ERR_EMAIL_IS_INCORRECT);
- return FALSE;
- }
- else
- {
- $params['id'] = $user_id;
- }
- }
- //账号注册时需要开启事务,避免出现垃圾数据
- Db::startTrans();
- try
- {
- $ret = $this->user->save($params);
- Db::commit();
- // 此时的Model中只包含部分数据
- $this->user = $this->user->get($this->user->id);
- $this->keeptime($keeptime);
- return $this->syncLogin();
- }
- catch (Exception $e)
- {
- Db::rollback();
- return FALSE;
- }
- }
- /**
- * 用户登录
- *
- * @param string $account 账号,用户名、邮箱、手机号
- * @param string $password 密码
- * @param int $keeptime 有效时长,默认为浏览器关闭
- * @return array
- */
- public function login($account, $password, $keeptime = 0, $sync = TRUE)
- {
- $field = Validate::is($account, 'email') ? 'email' : (Validate::regex($account, '/^1\d{10}$/') ? 'mobile' : 'username');
- $user = $this->user->get([$field => $account]);
- if ($user)
- {
- if ($user->status != 'normal')
- {
- $this->setError(self::ERR_ACCOUNT_IS_LOCKED);
- return FALSE;
- }
- if ($user->password != $this->getEncryptPassword($password, $user->salt))
- {
- $this->setError(self::ERR_PASSWORD_IS_INCORRECT);
- return FALSE;
- }
- $this->user = $user;
- // 设置登录有效时长
- $this->keeptime($keeptime);
- return $this->syncLogin($sync);
- }
- else
- {
- $this->setError(self::ERR_ACCOUNT_IS_INCORRECT);
- return FALSE;
- }
- }
- /**
- * 注销登录退出
- * @return bool
- */
- public function logout($token = NULL)
- {
- //设置登录标识
- $this->_logined = FALSE;
- $token = is_null($token) ? Cookie::get('token') : $token;
- Token::delete($token);
- Cookie::delete('user_id');
- //Cookie::del('username');
- Cookie::delete('token');
- return TRUE;
- }
- /**
- * 生成Token
- * @return string
- */
- public function token()
- {
- //$token = Encrypt::aesEncode($this->keeptime . '|' . $expiretime, Config::get('encrypt', 'aes_key'), TRUE);
- $token = Random::uuid();
- Token::set($token, $this->user->id, $this->keeptime);
- return $token;
- }
- /**
- * 初始化
- *
- * @param int $user_id 会员ID,默认从Cookie中取
- * @param string $token 会员Token,默认从Cookie中取
- *
- * @return boolean
- */
- public function init($user_id = NULL, $token = NULL)
- {
- $user_id = $user_id ? $user_id : Cookie::get('user_id');
- $user_id = intval($user_id);
- if ($user_id > 0)
- {
- if ($this->_error)
- return FALSE;
- $user = $this->get($user_id);
- if (!$user)
- {
- $this->setError(self::ERR_ACCOUNT_NOT_EXIST);
- return FALSE;
- }
- if ($user['status'] != 'normal')
- {
- $this->setError(self::ERR_ACCOUNT_IS_LOCKED);
- return FALSE;
- }
- $token = $token ? $token : Cookie::get('token');
- if (!Token::check($token))
- {
- return FALSE;
- }
- $this->user = $user;
- $this->_logined = TRUE;
- return TRUE;
- }
- else
- {
- $this->setError(self::ERR_YOU_ARE_NOT_LOGGED_IN);
- return FALSE;
- }
- }
- /**
- * 检测是否登录
- *
- * @return boolean
- */
- public function check()
- {
- return $this->_logined;
- }
- /**
- * 检测是否登录
- *
- * @return boolean
- */
- public function isLogin()
- {
- return $this->check();
- }
- /**
- * 获取当前请求的URI
- * @return string
- */
- public function getRequestUri()
- {
- return $this->requestUri;
- }
- /**
- * 设置当前请求的URI
- * @param string $uri
- */
- public function setRequestUri($uri)
- {
- $this->requestUri = $uri;
- }
- /**
- * 第三方登录
- * @param string $platform
- * @param array $params
- * @param int $keeptime
- * @return boolean
- */
- public function connect($platform, $params = [], $keeptime = 0)
- {
- $time = time();
- $values = [
- 'platform' => $platform,
- 'openid' => $params['openid'],
- 'openname' => isset($params['userinfo']['nickname']) ? $params['userinfo']['nickname'] : '',
- 'access_token' => $params['access_token'],
- 'refresh_token' => $params['refresh_token'],
- 'expires_in' => $params['expires_in'],
- 'logintime' => $time,
- 'expiretime' => $time + $params['expires_in'],
- ];
- $this->keeptime($keeptime);
- $userthird = UserThird::get(['platform' => $platform, 'openid' => $params['openid']]);
- if ($userthird)
- {
- $this->user = $this->user->get($userthird['user_id']);
- if (!$this->user)
- {
- return FALSE;
- }
- $userthird->save($values);
- return $this->syncLogin();
- }
- else
- {
- // 先随机一个用户名,随后再变更为u+数字id
- $username = Random::alnum(20);
- $password = Random::alnum(6);
- // 默认注册一个会员
- $result = $this->register($username, $password, '', '', [], $keeptime);
- if (!$result)
- {
- return FALSE;
- }
- $userarr = ['username' => 'u' . $this->user->id];
- if (isset($params['userinfo']['nickname']))
- $userarr['nickname'] = $params['userinfo']['nickname'];
- if (isset($params['userinfo']['avatar']))
- $userarr['avatar'] = $params['userinfo']['avatar'];
- // 更新会员资料
- $this->user->save($userarr);
- // 保存第三方信息
- $values['user_id'] = $this->user->id;
- UserThird::create($values);
- // 写入登录Cookies和Token
- $this->writeStatus();
- return TRUE;
- }
- }
- /**
- * 删除一个指定会员
- * @param int $user_id
- * @param bool $sync 是否同步删除
- */
- public function delete($user_id, $sync = TRUE)
- {
- $user = $this->user->get($user_id);
- if (!$user)
- {
- return FALSE;
- }
- ////////////////同步到Ucenter////////////////
- if (defined('UC_STATUS') && UC_STATUS && $sync)
- {
- $uc = new Client();
- $re = $uc->uc_user_delete($user['id']);
- // 如果小于0则说明发生错误
- if ($re <= 0)
- {
- $this->setError(self::ERR_ACCOUNT_IS_LOCKED);
- return FALSE;
- }
- }
- // 调用事务删除账号
- $result = Db::transaction(function($db) use($user_id)
- {
- // 删除会员
- User::destroy($user_id);
- // 删除会员第三方登录
- UserThird::destroy($user_id);
- });
- return $result ? TRUE : FALSE;
- }
- /**
- * 直接登录账号
- * @param int $user_id
- * @param boolean $sync
- * @return boolean
- */
- public function direct($user_id, $sync = TRUE)
- {
- $this->user = $this->user->get($user_id);
- if ($this->user)
- {
- $this->syncLogin($sync);
- return TRUE;
- }
- else
- {
- return FALSE;
- }
- }
- /**
- * 获取密码加密方式
- * @param string $password
- * @param string $salt
- * @return string
- */
- public function getEncryptPassword($password, $salt = '')
- {
- return md5(md5($password) . $salt);
- }
- /**
- * 同步登录信息
- * @param int $sync 是否同步登录到UC
- * @return boolean
- */
- protected function syncLogin($sync = TRUE)
- {
- ////////////////同步到Ucenter////////////////
- if (defined('UC_STATUS') && UC_STATUS && $sync)
- {
- $uc = new Client();
- $re = $uc->uc_user_login($this->user->id, $this->user->password . '#split#' . $this->user->salt, 3);
- // 如果小于0则说明发生错误
- if ($re <= 0)
- {
- $this->setError(self::ERR_USERNAME_OR_PASSWORD_IS_INCORRECT);
- return FALSE;
- }
- }
- //增加登录次数和设置最后登录时间
- $this->user->save([
- 'prevtime' => $this->user->logintime,
- 'logintime' => time(),
- 'loginip' => request()->ip(),
- ]);
- // 写入登录Cookies和Token
- $this->writeStatus();
- return TRUE;
- }
- /**
- * 写入登录态和Cookie
- *
- * @param int $keeptime
- */
- protected function writeStatus()
- {
- //设置登录标识
- $this->_logined = TRUE;
- $token = $this->token();
- Cookie::set('user_id', $this->user->id, $this->keeptime);
- Cookie::set('username', $this->user->username, 86400 * 365);
- //加密安全字符
- Cookie::set('token', $token, $this->keeptime);
- $this->setError('');
- }
- /**
- * 设置会话有效时间
- * @param int $keeptime 默认为永久
- */
- public function keeptime($keeptime = 0)
- {
- $this->keeptime = $keeptime;
- }
- /**
- * 渲染用户数据
- * @param array $datalist
- * @param array $fields
- * @param string $fieldkey
- * @param string $renderkey
- * @return array
- */
- public function render(&$datalist, $fields = [], $fieldkey = 'user_id', $renderkey = 'userinfo')
- {
- $fields = !$fields ? ['id', 'nickname', 'level', 'avatar'] : (is_array($fields) ? $fields : explode(',', $fields));
- $ids = [];
- foreach ($datalist as $k => $v)
- {
- if (!isset($v[$fieldkey]))
- continue;
- $ids[] = $v[$fieldkey];
- }
- $list = [];
- if ($ids)
- {
- if (!in_array('id', $fields))
- {
- $fields[] = 'id';
- }
- $ids = array_unique($ids);
- $selectlist = User::where('id', 'in', $ids)->column($fields);
- foreach ($selectlist as $k => $v)
- {
- $list[$v['id']] = $v;
- }
- }
- foreach ($datalist as $k => &$v)
- {
- $v[$renderkey] = isset($list[$v[$fieldkey]]) ? $list[$v[$fieldkey]] : NULL;
- }
- unset($v);
- return $datalist;
- }
- /**
- * 设置错误信息
- *
- * @param $error
- */
- public function setError($error)
- {
- $this->_error = $error;
- return $this;
- }
- /**
- * 获取错误信息
- * @return string
- */
- public function getError()
- {
- return __($this->_error);
- }
- }
|