LoginServices.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\services\user;
  13. use app\services\BaseServices;
  14. use app\dao\user\UserDao;
  15. use app\services\coupon\StoreCouponIssueServices;
  16. use app\services\message\sms\SmsRecordServices;
  17. use app\services\message\sms\SmsSendServices;
  18. use app\services\wechat\WechatUserServices;
  19. use app\jobs\RoutineTemplateJob;
  20. use app\jobs\WechatTemplateJob as TemplateJob;
  21. use crmeb\services\CacheService;
  22. use think\exception\ValidateException;
  23. use think\facade\Config;
  24. /**
  25. *
  26. * Class LoginServices
  27. * @package app\services\user
  28. */
  29. class LoginServices extends BaseServices
  30. {
  31. /**
  32. * LoginServices constructor.
  33. * @param LoginDao $dao
  34. */
  35. public function __construct(UserDao $dao)
  36. {
  37. $this->dao = $dao;
  38. }
  39. /**
  40. * H5账号登陆
  41. * @param Request $request
  42. * @return mixed
  43. * @throws \think\db\exception\DataNotFoundException
  44. * @throws \think\db\exception\ModelNotFoundException
  45. * @throws \think\exception\DbException
  46. */
  47. public function login($account, $password, $spread)
  48. {
  49. $user = $this->dao->getOne(['account|phone' => $account]);
  50. if ($user) {
  51. if ($user->pwd !== md5((string)$password))
  52. throw new ValidateException('账号或密码错误');
  53. if ($user->pwd === md5('123456'))
  54. throw new ValidateException('请修改您的初始密码,再尝试登录!');
  55. } else {
  56. throw new ValidateException('账号或密码错误');
  57. }
  58. if (!$user['status'])
  59. throw new ValidateException('已被禁止,请联系管理员');
  60. //更新用户信息
  61. $this->updateUserInfo(['code' => $spread], $user);
  62. $token = $this->createToken((int)$user['uid'], 'api');
  63. if ($token) {
  64. return ['token' => $token['token'], 'expires_time' => $token['params']['exp']];
  65. } else
  66. throw new ValidateException('登录失败');
  67. }
  68. /**
  69. * 更新用户信息
  70. * @param $user
  71. * @param $uid
  72. * @return bool
  73. * @throws \think\db\exception\DataNotFoundException
  74. * @throws \think\db\exception\DbException
  75. * @throws \think\db\exception\ModelNotFoundException
  76. */
  77. public function updateUserInfo($user, $userInfo)
  78. {
  79. $data = [];
  80. $data['nickname'] = !isset($user['nickname']) || !$user['nickname'] ? $userInfo->nickname : $user['nickname'];
  81. $data['avatar'] = !isset($user['headimgurl']) || !$user['headimgurl'] ? $userInfo->avatar : $user['headimgurl'];
  82. $data['phone'] = !isset($user['phone']) || !$user['phone'] ? $userInfo->phone : $user['phone'];
  83. $data['last_time'] = time();
  84. $data['last_ip'] = app()->request->ip();
  85. if ($userInfo->spread_uid) {
  86. $data['login_type'] = $user['login_type'] ?? $userInfo->login_type;
  87. } else {
  88. //绑定分销关系 = 所有用户
  89. if (sys_config('brokerage_bindind', 1) == 1) {
  90. $spreadUid = isset($user['code']) && $user['code'] && $user['code'] != $userInfo->uid ? $user['code'] : 0;
  91. if ($spreadUid && $userInfo->uid == $this->dao->value(['uid' => $spreadUid], 'spread_uid')) {
  92. $spreadUid = 0;
  93. }
  94. if ($spreadUid) {
  95. $spreadUid = (int)$spreadUid;
  96. $data['spread_uid'] = $spreadUid;
  97. $data['spread_time'] = $userInfo->last_time;
  98. $this->dao->incField($spreadUid, 'spread_count', 1);
  99. //绑定用户后置事件
  100. event('user.register', [$spreadUid, $userInfo['user_type'], $userInfo['nickname'], $userInfo['uid'], 0]);
  101. }
  102. }
  103. }
  104. if (!$this->dao->update($userInfo['uid'], $data, 'uid')) {
  105. throw new ValidateException('修改信息失败');
  106. }
  107. return true;
  108. }
  109. public function verify(SmsSendServices $services, $phone, $type, $time, $ip)
  110. {
  111. if ($this->dao->getOne(['account' => $phone]) && $type == 'register') {
  112. throw new ValidateException('手机号已注册');
  113. }
  114. $default = Config::get('sms.default', 'yunxin');
  115. $defaultMaxPhoneCount = Config::get('sms.maxPhoneCount', 10);
  116. $defaultMaxIpCount = Config::get('sms.maxIpCount', 50);
  117. $maxPhoneCount = Config::get('sms.stores.' . $default . '.maxPhoneCount', $defaultMaxPhoneCount);
  118. $maxIpCount = Config::get('sms.stores.' . $default . '.maxIpCount', $defaultMaxIpCount);
  119. /** @var SmsRecordServices $smsRecord */
  120. $smsRecord = app()->make(SmsRecordServices::class);
  121. if ($smsRecord->count(['phone' => $phone, 'add_ip' => $ip, 'time' => 'today']) >= $maxPhoneCount) {
  122. throw new ValidateException('您今日发送得短信次数已经达到上限');
  123. }
  124. if ($smsRecord->count(['add_ip' => $ip, 'time' => 'today']) >= $maxIpCount) {
  125. throw new ValidateException('此IP今日发送次数已经达到上限');
  126. }
  127. // if (CacheService::get('code_' . $phone))
  128. // throw new ValidateException($time . '分钟内有效');
  129. $code = rand(100000, 999999);
  130. $data['code'] = $code;
  131. $data['time'] = $time;
  132. $res = $services->send(true, $phone, $data, 'VERIFICATION_CODE_TIME');
  133. if ($res !== true)
  134. throw new ValidateException('短信平台验证码发送失败' . $res);
  135. return $code;
  136. }
  137. /**
  138. * H5用户注册
  139. * @param $account
  140. * @param $password
  141. * @param $spread
  142. * @return User|\think\Model
  143. */
  144. public function register($account, $password, $spread, $user_type = 'h5')
  145. {
  146. if ($this->dao->getOne(['account|phone' => $account])) {
  147. throw new ValidateException('用户已存在,请去修改密码');
  148. }
  149. $phone = $account;
  150. $data['account'] = $account;
  151. $data['pwd'] = md5((string)$password);
  152. $data['phone'] = $phone;
  153. if ($spread) {
  154. $data['spread_uid'] = $spread;
  155. $data['spread_time'] = time();
  156. /** @var UserBillServices $userBill */
  157. $userBill = app()->make(UserBillServices::class);
  158. //邀请新用户增加经验
  159. $userBill->inviteUserIncExp((int)$spread);
  160. }
  161. $data['real_name'] = '';
  162. $data['birthday'] = 0;
  163. $data['card_id'] = '';
  164. $data['mark'] = '';
  165. $data['addres'] = '';
  166. $data['user_type'] = $user_type;
  167. $data['add_time'] = time();
  168. $data['add_ip'] = app('request')->ip();
  169. $data['last_time'] = time();
  170. $data['last_ip'] = app('request')->ip();
  171. $data['nickname'] = substr(md5($account . time()), 0, 12);
  172. $data['avatar'] = $data['headimgurl'] = sys_config('h5_avatar');
  173. $data['city'] = '';
  174. $data['language'] = '';
  175. $data['province'] = '';
  176. $data['country'] = '';
  177. $data['status'] = 1;
  178. if (!$re = $this->dao->save($data)) {
  179. throw new ValidateException('注册失败');
  180. } else {
  181. //新人券发放
  182. event('user.giveNewUserCoupon', [$re->uid]);
  183. return $re;
  184. }
  185. }
  186. /**
  187. * 重置密码
  188. * @param $account
  189. * @param $password
  190. */
  191. public function reset($account, $password)
  192. {
  193. $user = $this->dao->getOne(['account|phone' => $account]);
  194. if (!$user) {
  195. throw new ValidateException('用户不存在');
  196. }
  197. if (!$this->dao->update($user['uid'], ['pwd' => md5((string)$password)], 'uid')) {
  198. throw new ValidateException('修改密码失败');
  199. }
  200. return true;
  201. }
  202. /**
  203. * 手机号登录
  204. * @param $phone
  205. * @param $spread
  206. * @return array
  207. * @throws \think\db\exception\DataNotFoundException
  208. * @throws \think\db\exception\DbException
  209. * @throws \think\db\exception\ModelNotFoundException
  210. */
  211. public function mobile($phone, $spread, $user_type = 'h5')
  212. {
  213. //数据库查询
  214. $user = $this->dao->getOne(['phone' => $phone]);
  215. if (!$user) {
  216. $user = $this->register($phone, '123456', $spread, $user_type);
  217. if (!$user) {
  218. throw new ValidateException('用户登录失败,无法生成新用户,请稍后再试!');
  219. }
  220. }
  221. if (!$user->status)
  222. throw new ValidateException('已被禁止,请联系管理员');
  223. // 设置推广关系
  224. $this->updateUserInfo(['code' => $spread], $user);
  225. $token = $this->createToken((int)$user['uid'], 'api');
  226. if ($token) {
  227. return ['token' => $token['token'], 'expires_time' => $token['params']['exp']];
  228. } else {
  229. throw new ValidateException('登录失败');
  230. }
  231. }
  232. /**
  233. * 切换登录
  234. * @param $user
  235. * @param $from
  236. */
  237. public function switchAccount($user, $from)
  238. {
  239. if ($from === 'h5') {
  240. $where = [['phone', '=', $user['phone']], ['user_type', '<>', 'h5']];
  241. $login_type = 'wechat';
  242. } else {
  243. //数据库查询
  244. $where = [['account|phone', '=', $user['phone']], ['user_type', '=', 'h5']];
  245. $login_type = 'h5';
  246. }
  247. $switch_user = $this->dao->getOne($where);
  248. if (!$switch_user) {
  249. return app('json')->fail('用户不存在,无法切换');
  250. }
  251. if (!$switch_user->status) {
  252. return app('json')->fail('已被禁止,请联系管理员');
  253. }
  254. $edit_data = ['login_type' => $login_type];
  255. if (!$this->dao->update($switch_user['uid'], $edit_data, 'uid')) {
  256. throw new ValidateException('修改新用户登录类型出错');
  257. }
  258. $token = $this->createToken((int)$switch_user['uid'], 'api');
  259. if ($token) {
  260. return ['token' => $token['token'], 'expires_time' => $token['params']['exp']];
  261. } else {
  262. throw new ValidateException('切换失败');
  263. }
  264. }
  265. /**
  266. * 绑定手机号(静默还没写入用户信息)
  267. * @param $user
  268. * @param $phone
  269. * @param $step
  270. * @return mixed
  271. */
  272. public function bindind_phone($phone, $key = '')
  273. {
  274. if (!$key) {
  275. throw new ValidateException('请刷新页面或者重新授权');
  276. }
  277. [$openid, $wechatInfo, $spreadId, $login_type, $userType] = $createData = CacheService::getTokenBucket($key);
  278. if (!$createData) {
  279. throw new ValidateException('请刷新页面或者重新授权');
  280. }
  281. $wechatInfo['phone'] = $phone;
  282. /** @var WechatUserServices $wechatUser */
  283. $wechatUser = app()->make(WechatUserServices::class);
  284. //更新用户信息
  285. $user = $wechatUser->wechatOauthAfter([$openid, $wechatInfo, $spreadId, $login_type, $userType]);
  286. $token = $this->createToken((int)$user['uid'], $userType);
  287. if ($token) {
  288. return [
  289. 'token' => $token['token'],
  290. 'userInfo' => $user,
  291. 'expires_time' => $token['params']['exp'],
  292. ];
  293. } else
  294. return app('json')->fail('获取用户访问token失败!');
  295. }
  296. /**
  297. * 用户绑定手机号
  298. * @param $user
  299. * @param $phone
  300. * @param $step
  301. * @return mixed
  302. */
  303. public function userBindindPhone(int $uid, $phone, $step)
  304. {
  305. $userInfo = $this->dao->get($uid);
  306. if (!$userInfo) {
  307. throw new ValidateException('用户不存在');
  308. }
  309. if ($this->dao->getOne([['phone', '=', $phone], ['user_type', '<>', 'h5']])) {
  310. throw new ValidateException('此手机已经绑定,无法多次绑定!');
  311. }
  312. if ($userInfo->phone) {
  313. throw new ValidateException('您的账号已经绑定过手机号码!');
  314. }
  315. $data = [];
  316. if ($this->dao->getOne(['account' => $phone, 'phone' => $phone, 'user_type' => 'h5'])) {
  317. if (!$step) return ['msg' => 'H5已有账号是否绑定此账号上', 'data' => ['is_bind' => 1]];
  318. } else {
  319. $data['account'] = $phone;
  320. }
  321. $data['phone'] = $phone;
  322. if ($this->dao->update($userInfo['uid'], $data, 'uid') || $userInfo->phone == $phone)
  323. return ['msg' => '绑定成功', 'data' => []];
  324. else
  325. throw new ValidateException('绑定失败');
  326. }
  327. /**
  328. * 用户绑定手机号
  329. * @param $user
  330. * @param $phone
  331. * @param $step
  332. * @return mixed
  333. */
  334. public function updateBindindPhone(int $uid, $phone)
  335. {
  336. $userInfo = $this->dao->get($uid);
  337. if (!$userInfo) {
  338. throw new ValidateException('用户不存在');
  339. }
  340. if ($userInfo->phone == $phone) {
  341. throw new ValidateException('新手机号和原手机号相同,无需修改');
  342. }
  343. if ($this->dao->getOne([['phone', '=', $phone]])) {
  344. throw new ValidateException('此手机已经注册');
  345. }
  346. $data = [];
  347. $data['phone'] = $phone;
  348. if ($this->dao->update($userInfo['uid'], $data, 'uid'))
  349. return ['msg' => '修改成功', 'data' => []];
  350. else
  351. throw new ValidateException('修改失败');
  352. }
  353. }