Auth.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // |
  4. // +----------------------------------------------------------------------
  5. // |
  6. // +----------------------------------------------------------------------
  7. // |
  8. // +----------------------------------------------------------------------
  9. // |
  10. // +----------------------------------------------------------------------
  11. // | Original reference: https://gitee.com/karson/fastadmin
  12. // +----------------------------------------------------------------------
  13. // +----------------------------------------------------------------------
  14. // | 前台用户服务
  15. // +----------------------------------------------------------------------
  16. namespace app\common\library;
  17. use app\common\model\User;
  18. use app\common\model\UserGroup;
  19. use think\facade\Config;
  20. use think\facade\Db;
  21. use think\facade\Event;
  22. use think\facade\Validate;
  23. use util\Random;
  24. class Auth
  25. {
  26. protected static $instance = null;
  27. protected $_error = '';
  28. protected $_logined = false;
  29. protected $_user = null;
  30. protected $_token = '';
  31. //Token默认有效时长
  32. protected $keeptime = 2592000;
  33. protected $requestUri = '';
  34. protected $rules = [];
  35. //默认配置
  36. protected $config = [];
  37. protected $options = [];
  38. protected $allowFields = ['id', 'username', 'nickname', 'mobile', 'avatar', 'point', 'amount'];
  39. public function __construct($options = [])
  40. {
  41. if ($config = Config::get('user')) {
  42. $this->config = array_merge($this->config, $config);
  43. }
  44. $this->options = array_merge($this->config, $options);
  45. }
  46. /**
  47. *
  48. * @param array $options 参数
  49. * @return Auth
  50. */
  51. public static function instance($options = [])
  52. {
  53. if (is_null(self::$instance)) {
  54. self::$instance = new static($options);
  55. }
  56. return self::$instance;
  57. }
  58. /**
  59. * 获取User模型
  60. * @return User
  61. */
  62. public function getUser()
  63. {
  64. return $this->_user;
  65. }
  66. /**
  67. * 兼容调用user模型的属性
  68. *
  69. * @param string $name
  70. * @return mixed
  71. */
  72. public function __get($name)
  73. {
  74. return $this->_user ? $this->_user->$name : null;
  75. }
  76. /**
  77. * 兼容调用user模型的属性
  78. */
  79. public function __isset($name)
  80. {
  81. return isset($this->_user) ? isset($this->_user->$name) : false;
  82. }
  83. /**
  84. * 根据Token初始化
  85. *
  86. * @param string $token Token
  87. * @return boolean
  88. */
  89. public function init($token)
  90. {
  91. if ($this->_logined) {
  92. return true;
  93. }
  94. if ($this->_error) {
  95. return false;
  96. }
  97. $data = Token::get($token);
  98. if (!$data) {
  99. return false;
  100. }
  101. $user_id = intval($data['user_id']);
  102. if ($user_id > 0) {
  103. $user = User::find($user_id);
  104. if (!$user) {
  105. $this->setError('账户不存在');
  106. return false;
  107. }
  108. if ($user['status'] !== 1) {
  109. $this->setError('账户已经被锁定');
  110. return false;
  111. }
  112. $this->_user = $user;
  113. $this->_logined = true;
  114. $this->_token = $token;
  115. //初始化成功的事件
  116. Event::trigger("user_init_successed", $this->_user);
  117. return true;
  118. } else {
  119. $this->setError('你当前还未登录');
  120. return false;
  121. }
  122. }
  123. /**
  124. * 注册一个新用户
  125. * @param $username 用户名
  126. * @param $password 密码
  127. * @param string $email 邮箱
  128. * @param string $mobile 手机号
  129. * @param array $extend 扩展参数
  130. * @return bool|mixed
  131. */
  132. public function register($username, $password, $email = '', $mobile = '', $extend = [])
  133. {
  134. $ip = request()->ip();
  135. $passwordinfo = encrypt_password($password); //对密码进行处理
  136. $data = [
  137. "mobile" => $mobile,
  138. "username" => $username,
  139. "email" => $email,
  140. "encrypt" => $passwordinfo['encrypt'],
  141. "amount" => 0,
  142. ];
  143. $nickname = $extend['nickname'] ?? $username;
  144. $extend['nickname'] = preg_match("/^1[3-9]\d{9}$/", $nickname) ? substr_replace($nickname, '****', 3, 4) : $nickname;
  145. //新注册用户积分
  146. $data['point'] = Config::get('yzn.user_defualt_point') ?: 0;
  147. //新会员注册默认赠送资金
  148. $data['amount'] = Config::get('yzn.user_defualt_amount') ?: 0;
  149. //新会员注册需要管理员审核
  150. $data['status'] = Config::get('yzn.user_register_verify') ? 0 : 1;
  151. //计算用户组
  152. $data['group_id'] = $this->get_usergroup_bypoint($data['point']);
  153. $params = array_merge($data, $extend);
  154. $params['password'] = $passwordinfo['password'];
  155. $params['reg_ip'] = $ip;
  156. $params['last_login_ip'] = $ip;
  157. //账号注册时需要开启事务,避免出现垃圾数据
  158. Db::startTrans();
  159. try {
  160. $user = User::create($params);
  161. $this->_user = User::find($user->id);
  162. //设置Token
  163. $this->_token = Random::uuid($user->id);
  164. Token::set($this->_token, $user->id, $this->keeptime);
  165. //设置登录状态
  166. $this->_logined = true;
  167. //注册成功的事件
  168. Event::trigger("user_register_successed", $this->_user);
  169. Db::commit();
  170. } catch (\Exception $e) {
  171. Db::rollback();
  172. $this->setError($e->getMessage());
  173. return false;
  174. }
  175. return $user->id;
  176. }
  177. /**
  178. * 会员登录
  179. * @param $account 账户
  180. * @param $password 明文密码,填写表示验证密码
  181. * @return boolean
  182. */
  183. public function login($account, $password = null)
  184. {
  185. $field = Validate::is($account, 'email') ? 'email' : (Validate::regex($account, '/^1\d{10}$/') ? 'mobile' : 'username');
  186. $user = User::where([$field => $account])->find();
  187. if (!$user) {
  188. $this->setError('账户不正确');
  189. return false;
  190. }
  191. if ($user->status !== 1) {
  192. $this->setError('账户已经被锁定');
  193. return false;
  194. }
  195. if ($user->password != encrypt_password($password, $user->encrypt)) {
  196. $this->setError('密码不正确');
  197. return false;
  198. }
  199. //直接登录会员
  200. $this->direct($user->id);
  201. return true;
  202. }
  203. /**
  204. * 注销登录状态
  205. * @return boolean
  206. */
  207. public function logout()
  208. {
  209. if (!$this->_logined) {
  210. $this->setError('你当前还未登录');
  211. return false;
  212. }
  213. //设置登录标识
  214. $this->_logined = false;
  215. //删除Token
  216. Token::delete($this->_token);
  217. //退出成功的事件
  218. Event::trigger("user_logout_successed", $this->_user);
  219. return true;
  220. }
  221. /**
  222. * 修改密码
  223. * @param string $newpassword 新密码
  224. * @param string $oldpassword 旧密码
  225. * @param bool $ignoreoldpassword 忽略旧密码
  226. * @return boolean
  227. */
  228. public function changepwd($newpassword, $oldpassword = '', $ignoreoldpassword = false)
  229. {
  230. if (!$this->_logined) {
  231. $this->setError('你当前还未登录');
  232. return false;
  233. }
  234. //判断旧密码是否正确
  235. if ($this->_user->password == encrypt_password($oldpassword, $this->_user->encrypt) || $ignoreoldpassword) {
  236. Db::startTrans();
  237. try {
  238. $encrypt = Random::alnum();
  239. $newpassword = encrypt_password($newpassword, $encrypt);
  240. $this->_user->save(['password' => $newpassword, 'encrypt' => $encrypt]);
  241. Token::clear($this->_user->id);
  242. //修改密码成功的事件
  243. Event::trigger("user_changepwd_successed", $this->_user);
  244. Db::commit();
  245. } catch (Exception $e) {
  246. Db::rollback();
  247. $this->setError($e->getMessage());
  248. return false;
  249. }
  250. return true;
  251. } else {
  252. $this->setError('密码不正确');
  253. return false;
  254. }
  255. }
  256. /**
  257. * 直接登录账号
  258. * @param int $user_id
  259. * @return boolean
  260. */
  261. public function direct($user_id)
  262. {
  263. $user = User::find($user_id);
  264. if ($user) {
  265. Db::startTrans();
  266. try {
  267. $ip = request()->ip();
  268. $time = time();
  269. //更新会员组
  270. $check_groupid = $this->get_usergroup_bypoint($user->point);
  271. if ($check_groupid != $user->group_id) {
  272. $user->group_id = $check_groupid;
  273. }
  274. //记录本次登录的IP和时间
  275. $user->last_login_ip = $ip;
  276. $user->last_login_time = $time;
  277. $user->login = $user->login + 1;
  278. $user->save();
  279. $this->_user = $user;
  280. $this->_token = Random::uuid($user->id);
  281. Token::set($this->_token, $user->id, $this->keeptime);
  282. $this->_logined = true;
  283. //登录成功的事件
  284. Event::trigger("user_login_successed", $this->_user);
  285. Db::commit();
  286. } catch (Exception $e) {
  287. Db::rollback();
  288. $this->setError($e->getMessage());
  289. return false;
  290. }
  291. return true;
  292. } else {
  293. return false;
  294. }
  295. }
  296. /**
  297. * 判断是否登录
  298. * @return boolean
  299. */
  300. public function isLogin()
  301. {
  302. if ($this->_logined) {
  303. return true;
  304. }
  305. return false;
  306. }
  307. /**
  308. * 获取当前Token
  309. * @return string
  310. */
  311. public function getToken()
  312. {
  313. return $this->_token;
  314. }
  315. /**
  316. * 获取会员基本信息
  317. */
  318. public function getUserinfo()
  319. {
  320. $data = $this->_user->toArray();
  321. $allowFields = $this->getAllowFields();
  322. $userinfo = array_intersect_key($data, array_flip($allowFields));
  323. $userinfo = array_merge($userinfo, Token::get($this->_token));
  324. return $userinfo;
  325. }
  326. /**
  327. * 获取当前请求的URI
  328. * @return string
  329. */
  330. public function getRequestUri()
  331. {
  332. return $this->requestUri;
  333. }
  334. /**
  335. * 设置当前请求的URI
  336. * @param string $uri
  337. */
  338. public function setRequestUri($uri)
  339. {
  340. $this->requestUri = $uri;
  341. }
  342. /**
  343. * 获取允许输出的字段
  344. * @return array
  345. */
  346. public function getAllowFields()
  347. {
  348. return $this->allowFields;
  349. }
  350. /**
  351. * 设置允许输出的字段
  352. * @param array $fields
  353. */
  354. public function setAllowFields($fields)
  355. {
  356. $this->allowFields = $fields;
  357. }
  358. /**
  359. * 删除一个指定会员
  360. * @param int $user_id 会员ID
  361. * @return boolean
  362. */
  363. public function delete($user_id)
  364. {
  365. $user = User::find($user_id);
  366. if (!$user) {
  367. return false;
  368. }
  369. Db::startTrans();
  370. try {
  371. // 删除会员
  372. User::destroy($user_id);
  373. // 删除会员指定的所有Token
  374. Token::clear($user_id);
  375. Event::trigger("user_delete_successed", $user);
  376. Db::commit();
  377. } catch (Exception $e) {
  378. Db::rollback();
  379. $this->setError($e->getMessage());
  380. return false;
  381. }
  382. return true;
  383. }
  384. /**
  385. * 检测当前控制器和方法是否匹配传递的数组
  386. *
  387. * @param array $arr 需要验证权限的数组
  388. * @return boolean
  389. */
  390. public function match($arr = [])
  391. {
  392. $arr = is_array($arr) ? $arr : explode(',', $arr);
  393. if (!$arr) {
  394. return false;
  395. }
  396. $arr = array_map('strtolower', $arr);
  397. // 是否存在
  398. if (in_array(strtolower(request()->action()), $arr) || in_array('*', $arr)) {
  399. return true;
  400. }
  401. // 没找到匹配
  402. return false;
  403. }
  404. /**
  405. * 根据积分算出用户组
  406. * @param int $point 积分数
  407. * @return int|string|null
  408. */
  409. public function get_usergroup_bypoint($point = 0)
  410. {
  411. $groupid = 1;
  412. if (empty($point)) {
  413. //新会员默认点数
  414. $point = Config::get('yzn.user_defualt_point') ?: 0;
  415. }
  416. $groups = UserGroup::order('point ASC')->column('point', 'id');
  417. foreach ($groups as $key => $value) {
  418. if ($point >= $value) {
  419. $groupid = $key;
  420. }
  421. }
  422. return $groupid;
  423. }
  424. /**
  425. * 设置会话有效时间
  426. * @param int $keeptime 默认为永久
  427. */
  428. public function keeptime($keeptime = 0)
  429. {
  430. $this->keeptime = $keeptime;
  431. }
  432. /**
  433. * 设置错误信息
  434. *
  435. * @param string $error 错误信息
  436. * @return Auth
  437. */
  438. public function setError($error)
  439. {
  440. $this->_error = $error;
  441. return $this;
  442. }
  443. /**
  444. * 获取错误信息
  445. * @return string
  446. */
  447. public function getError()
  448. {
  449. return $this->_error ? $this->_error : '';
  450. }
  451. }