WechatForm.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. <?php
  2. namespace api\modules\v1\forms\user;
  3. use common\enums\StatusEnum;
  4. use common\events\user\UserLoginEvent;
  5. use common\events\user\UserRegisterEvent;
  6. use common\helpers\ArrayHelper;
  7. use common\models\user\User;
  8. use common\models\user\UserInfo;
  9. use common\traits\ErrorTrait;
  10. use yii\base\Model;
  11. use yii\db\Exception;
  12. class WechatForm extends Model
  13. {
  14. use ErrorTrait;
  15. public $mall_id = '';
  16. public function __construct($config = [])
  17. {
  18. parent::__construct($config);
  19. $wechat = \Yii::$app->services->setting->mall->get($config['mall_id'], 'wechat');
  20. if ($wechat) {
  21. \Yii::$app->params['wechatConfig'] = [
  22. 'app_id' => $wechat['app_id'] ?? '',
  23. 'secret' => $wechat['secret'] ?? '',
  24. 'token' => $wechat['token'] ?? '',
  25. 'aes_key' => $wechat['aes_key'] ?? '',
  26. ];
  27. }
  28. $mini_program = \Yii::$app->services->setting->mall->get($config['mall_id'], 'mini_program');
  29. if (!empty($mini_program)) {
  30. \Yii::$app->params['wechatMiniProgramConfig'] = [
  31. 'app_id' => $mini_program['app_id'],
  32. 'secret' => $mini_program['secret'],
  33. 'key' => $mini_program['pay_secret'] ?? '',
  34. 'cert_path' => $mini_program['cert_pem_path'] ?? '',
  35. 'key_path' => $mini_program['key_pem_path'] ?? '',
  36. 'notify_url' => ''//回调地址
  37. ];
  38. }
  39. $payment = \Yii::$app->services->setting->mall->get($config['mall_id'], 'pay.wechat');
  40. $payment = json_decode($payment, true);
  41. if (!empty($payment["wechat_status"]) && $payment["wechat_status"] == 1) {
  42. $wechatOpenAppId = isset($payment['wechat_open_app_id']) ? $payment['wechat_open_app_id'] : "";
  43. \Yii::$app->params['wechatPaymentConfig'] = [
  44. 'app_id' => $payment['wechat_app_id']??0,
  45. 'mch_id' => $payment['wechat_mch_id']??0,
  46. 'key' => $payment['wechat_pay_secret']??'',
  47. 'cert_path' => $payment['wechat_cert_pem_path']??'',
  48. 'key_path' => $payment['wechat_key_pem_path']??'',
  49. 'notify_url' => ''//回调地址
  50. ];
  51. }
  52. }
  53. /**
  54. * @desc:app端微信授权登录,不登录,等关联手机号再进行登录
  55. * @Author: hua
  56. * @Date: 2021/10/22
  57. * @Time: 14:53
  58. * @Copyright: copyright (c) 2021 广东七件事集团
  59. * @param $params
  60. * @return array|false
  61. */
  62. public function appAuthLogin($params)
  63. {
  64. try {
  65. //前端授权登录成功后,发送的用户数据
  66. $result_data = json_decode($params["userData"], true);
  67. if (empty($result_data)) throw new Exception('授权失败');
  68. //授权成功获取用户数据 {"userInfo":{"openId":"","nickName":"","gender":0,"city":"","province":"","country":"","avatarUrl":"","unionId":""}}
  69. $params["openid"] = $result_data["openId"];
  70. $params["unionid"] = $result_data["unionId"];
  71. $params["nickname"] = $result_data["nickName"] ?? '微信用户';
  72. $params["headimgurl"] = $result_data["avatarUrl"];
  73. $params['platform'] = User::PLATFORM_APP;
  74. $data["nickName"] = $params["nickname"];
  75. $data["avatarUrl"] = $params["headimgurl"] ;
  76. $params['platform_data'] = $data;
  77. \Yii::error('appAuthLogin:'.json_encode($data));
  78. $result = self::checkIsAuthorized($params);
  79. if (empty($result)) throw new Exception(self::getStaticError());
  80. $return_data['openid'] = $params["openid"];
  81. if (!empty($result['user'])) {
  82. $user = $result['user'];
  83. \Yii::$app->user->login($user);
  84. $res = \Yii::$app->services->apiAccessToken->getAccessToken($user, 'api');
  85. $return_data['access_token'] = $res['access_token'];
  86. // 触发登录成功事件,事务提交完成后触发
  87. $event = new UserLoginEvent($user['mall_id']);
  88. \Yii::$app->services->events->dispatch($event, [
  89. 'mall_id' => $user['mall_id'],
  90. 'nickname' => $user['nickname'],
  91. 'user_id' => $user['id'],
  92. 'platform' => $user['platform'],
  93. 'ip' => ArrayHelper::get_client_ip(),
  94. 'device_type' => $params['device_type'] ?? '',
  95. 'device_mac' => $params['device_mac'] ?? '',
  96. ], $event->listeners);
  97. }
  98. return $return_data;
  99. } catch (\Exception $e) {
  100. \Yii::error("appAuthLogin error=" . $e->getFile() . ";line:" . $e->getLine() . ";message:" . $e->getMessage());
  101. self::$static_error = $e->getMessage();
  102. return false;
  103. }
  104. }
  105. /**
  106. * @desc:授权
  107. * @Author: hua
  108. * @Date: 2021/10/25
  109. * @Time: 11:21
  110. * @Copyright: copyright (c) 2021 广东七件事集团
  111. * @param $params
  112. * @return array|false
  113. */
  114. public static function checkIsAuthorized($params)
  115. {
  116. try {
  117. $where = [['mall_id' => $params['mall_id']], ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]];
  118. if (!empty($params["openid"])) {
  119. $where[] = ['openid' => $params["openid"]];
  120. } else if (!empty($params["unionid"])) {
  121. $where[] = ['unionid' => $params["unionid"]];
  122. }
  123. if (!empty($params["platform"])) $where[] = ['platform' => $params["platform"]];
  124. $user_info = UserInfo::getOne($where);
  125. \Yii::info('授权参数:'.json_encode($params));
  126. $user = User::findOne(['id' => $user_info->user_id]);
  127. if (empty($user_info) || empty($user_info->user_id) || ($user && empty($user->mobile))) {
  128. // 将旧的openid删除
  129. $other_where = $where = ['mall_id' => $params['mall_id'], 'unionid' => $params["unionid"], 'status' => StatusEnum::ENABLED];
  130. if (!empty($params["platform"])) $where['platform'] =$params["platform"];
  131. if (!empty($params["openid"])) $where['openid'] =$params["openid"];
  132. UserInfo::updateAll(['status' => StatusEnum::DELETE],$where);
  133. $params['user_id'] = 0;
  134. //小鹅通特殊操作
  135. if (!empty($user_info->user_id)) {
  136. $params['user_id'] = $user_info->user_id;
  137. }
  138. $res = UserInfo::setData($params);
  139. if ($res === false) throw new Exception('授权失败');
  140. if(!empty($params["unionid"])){
  141. $other_platform = UserInfo::find()->where($other_where)->one();// 通过unionid获取其他渠道的user_id
  142. if ($other_platform && $other_platform->user_id) {
  143. $user = User::findOne($other_platform->user_id);
  144. if ($user && !empty($user->mobile)) {
  145. if(!empty($params['share_user_id'])&&empty($user->parent_id)){
  146. $user->temp_parent_id = $params['share_user_id'];
  147. }
  148. $user->last_login_at = time();
  149. $user->save();
  150. // 将当前渠道的user_info字段填充
  151. $res->user_id = $other_platform->user_id;
  152. if (!$res->save()) \Yii::error("user-info保存失败:" . $res->getErrorMessage());
  153. return ['user' => $user];
  154. }
  155. }
  156. }
  157. return ['user' => null];
  158. } else {
  159. //之前获取不到微信昵称和头像则更新用户昵称和头像
  160. $user = User::findOne($user_info->user_id);
  161. if ($user) {
  162. if($user['status']==0) throw new \Exception('账号已注销');
  163. // if ($user->nickname == "微信用户") {
  164. // $user->nickname = isset($params["nickname"]) ? (string)$params["nickname"] : "";
  165. // $user->avatar_url = isset($params["headimgurl"]) ? $params["headimgurl"] : "";
  166. // }
  167. if(!empty($params['share_user_id'])&&empty($user->parent_id)){
  168. $user->temp_parent_id = $params['share_user_id'];
  169. }
  170. $user->last_login_at = time();
  171. $user->save();
  172. }
  173. if (empty($user_info->unionid) && !empty($params['unionid'])) {
  174. $user_info->unionid = $params['unionid'];
  175. $user_info->save();
  176. }
  177. return ['user' => $user];
  178. }
  179. } catch (\Exception $e) {
  180. \Yii::error("error=" . $e->getFile() . ";line:" . $e->getLine() . ";message:" . $e->getMessage());
  181. self::$static_error = $e->getMessage();
  182. return false;
  183. }
  184. }
  185. /**
  186. * @desc:授权手机号码,同时登录
  187. * @Author: hua
  188. * @Date: 2021/10/25
  189. * @Time: 11:51
  190. * @Copyright: copyright (c) 2021 广东七件事集团
  191. * @param $params
  192. * @return array|false
  193. */
  194. public function authorizedMobilePhone($params)
  195. {
  196. // $t = \Yii::$app->db->beginTransaction();
  197. try {
  198. $wechatModel = \Yii::$app->wechat;
  199. $resultData = $wechatModel->miniProgram->auth->session($params['code']);
  200. $errmsg = $resultData['errmsg'] ?? '';
  201. if($errmsg){
  202. \Yii::error('auth session error:'.json_encode($resultData));
  203. throw new Exception($errmsg);
  204. }
  205. $sessionKey = $resultData["session_key"];
  206. $openid = $resultData["openid"];
  207. $iv = $params['iv'];
  208. $encrypted = $params['encryptedData'];
  209. $data = $wechatModel->miniProgram->encryptor->decryptData($sessionKey, $iv, $encrypted);
  210. \Yii::info('授权手机号返回信息:'.json_encode($data));
  211. $params['area_code'] = $data["countryCode"];// 区号
  212. $params['mobile'] = $data["purePhoneNumber"];// 不带区号的手机号码
  213. $where = [['mobile' => $params['mobile']], ['mall_id' => $params['mall_id']], ['status' => [StatusEnum::DISABLED, StatusEnum::ENABLED]]];
  214. $user = User::getOne($where);
  215. $user_info = UserInfo::findOne(['mall_id' => $params['mall_id'], 'openid' => $openid,'status'=>StatusEnum::ENABLED]);
  216. $platform_data = json_decode($user_info->platform_data, true);
  217. if (!empty($user)) {
  218. $res = UserInfo::findOne(['mall_id' => $params['mall_id'], 'user_id' => $user->id,'platform'=>$user_info->platform,'status'=>StatusEnum::ENABLED]);
  219. if (!empty($res)) throw new Exception('该手机号码已经被注册');
  220. $user_info->user_id = $user->id;
  221. if (empty($user_info->unionid) && !empty($params['unionid'])) {
  222. $user_info->unionid = $params['unionid'];
  223. }
  224. $res = $user_info->save();
  225. if ($res == false) throw new Exception(UserInfo::getStaticError());
  226. $user->nickname = (string)$platform_data['nickName'];
  227. $user->avatar_url = $platform_data['avatarUrl'];
  228. $user->platform = $user_info->platform;
  229. $res = $user->save();
  230. if ($res == false) throw new Exception(User::getStaticError());
  231. } else {
  232. //小鹅通特殊操作
  233. if ($user_info && $user_info->user_id) {
  234. $params['id'] = $user_info->user_id;
  235. $user = User::getOne([['id' => $user_info->user_id], ['status' => [StatusEnum::DISABLED, StatusEnum::ENABLED]]]);
  236. if ($user && $user->parent_id) {
  237. $params['parent_id'] = $user->parent_id;
  238. }
  239. }
  240. $password = substr($params['mobile'],-6,6);
  241. $params['password'] = \Yii::$app->getSecurity()->generatePasswordHash($password);
  242. $params["username"] = $params["mobile"];
  243. $params["openid"] = $platform_data["openid"];
  244. $params["unionid"] = $platform_data["unionid"] ?? '';
  245. $params["nickname"] = (string)$platform_data["nickName"];
  246. $params["headimgurl"] = $platform_data["avatarUrl"];
  247. $params["avatar_url"] = $platform_data["avatarUrl"];
  248. $params['platform'] = $user_info->platform;
  249. $params['last_login_at'] = time();
  250. $user = User::setData($params);
  251. if ($user == false) throw new Exception(User::getStaticError());
  252. // 小程序授权手机触发注册事件
  253. $event = new UserRegisterEvent($params['mall_id']);
  254. $data = ['user_id' => $user->id, 'platform' => $user->platform];
  255. \Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  256. $user_info->user_id = $user->id;
  257. $res = $user_info->save();
  258. if ($res == false) throw new Exception(UserInfo::getStaticError());
  259. }
  260. // $t->commit();
  261. \Yii::$app->user->login($user);
  262. // 触发登录成功事件,事务提交完成后触发
  263. $event = new UserLoginEvent($user->mall_id);
  264. \Yii::$app->services->events->dispatch($event, [
  265. 'mall_id' => $user->mall_id,
  266. 'nickname' => $user->nickname,
  267. 'user_id' => $user->id,
  268. 'platform' => $user->platform,
  269. 'ip' => ArrayHelper::get_client_ip(),
  270. 'device_type' => $params['device_type'] ?? '',
  271. 'device_mac' => $params['device_mac'] ?? '',
  272. ], $event->listeners);
  273. return \Yii::$app->services->apiAccessToken->getAccessToken($user, 'api');
  274. } catch (\Exception $e) {
  275. // $t->rollBack();
  276. self::$static_error = $e->getMessage();
  277. \Yii::error('绑定手机号错误:' . $e->getFile().',第'.$e->getLine().'行,原因:'.$e->getMessage());
  278. return false;
  279. }
  280. }
  281. /**
  282. * @desc:微信小程序授权,不登录,等授权手机号码再登录
  283. * @Author: hua
  284. * @Date: 2021/10/25
  285. * @Time: 11:50
  286. * @Copyright: copyright (c) 2021 广东七件事集团
  287. * @param $params
  288. * @return array|false
  289. */
  290. public function miniAuthorized($params)
  291. {
  292. try {
  293. $wechatModel = \Yii::$app->wechat;
  294. //微信小程序授权登录
  295. $result_data = $wechatModel->miniProgram->auth->session($params['code']);
  296. if (isset($result_data["errcode"]) && $result_data["errcode"] != 0) throw new Exception($result_data["errmsg"]);
  297. //授权成功获取sessiong_key
  298. $session_key = $result_data["session_key"];
  299. $iv = $params['iv'];
  300. $encrypted = $params['encryptedData'];
  301. //解密微信加密数据
  302. $data = $wechatModel->miniProgram->encryptor->decryptData($session_key, $iv, $encrypted);
  303. $openid = isset($data["openId"]) ? $data["openId"] : (isset($result_data["openid"]) ? $result_data["openid"] : "");
  304. if (empty($openid)) throw new Exception('缺少openid参数');
  305. $params["openid"] = $result_data["openid"];
  306. $params["unionid"] = $result_data["unionid"] ?? '';
  307. $params["nickname"] = $data["nickName"];
  308. $params["headimgurl"] = $data["avatarUrl"];
  309. $params["session_key"] = $session_key;
  310. $params['platform'] = User::PLATFORM_MP_WX;
  311. $params['platform_data'] = $data;
  312. $result = self::checkIsAuthorized($params);
  313. $return_data['openid'] = $result_data["openid"];
  314. if (empty($result)) throw new Exception(self::getStaticError());
  315. if (!empty($result['user'])) {
  316. $user = $result['user'];
  317. \Yii::$app->user->login($user);
  318. $res = \Yii::$app->services->apiAccessToken->getAccessToken($user, 'api');
  319. $return_data['access_token'] = $res['access_token'];
  320. // 触发登录成功事件,事务提交完成后触发
  321. $event = new UserLoginEvent($user['mall_id']);
  322. \Yii::$app->services->events->dispatch($event, [
  323. 'mall_id' => $user['mall_id'],
  324. 'nickname' => $user['nickname'],
  325. 'user_id' => $user['id'],
  326. 'platform' => $user['platform'],
  327. 'ip' => ArrayHelper::get_client_ip(),
  328. 'device_type' => $params['device_type'] ?? '',
  329. 'device_mac' => $params['device_mac'] ?? '',
  330. ], $event->listeners);
  331. }
  332. return $return_data;
  333. } catch (\Exception $e) {
  334. \Yii::error("miniAuthorized error=" . $e->getFile() . ";line:" . $e->getLine() . ";message:" . $e->getMessage());
  335. self::$static_error = $e->getMessage();
  336. return false;
  337. }
  338. }
  339. /**
  340. * @desc:微信授权,不登录,等关联手机号再进行登录
  341. * @Author: hua
  342. * @Date: 2021/10/22
  343. * @Time: 11:38
  344. * @Copyright: copyright (c) 2021 广东七件事集团
  345. * @param $params
  346. * @return array|false
  347. */
  348. public function authorized($params)
  349. {
  350. try {
  351. $return_data['access_token'] = '';
  352. $wechatModel = \Yii::$app->wechat;
  353. if (!$wechatModel->isWechat) throw new Exception('不是微信请求');
  354. $result = $wechatModel->app->oauth->user();
  355. if (!empty($result)) {
  356. $user_info = $result->original;
  357. $params["openid"] = $user_info["openid"];
  358. $params["nickname"] = $user_info["nickname"];
  359. $params["headimgurl"] = $user_info["headimgurl"];
  360. $params["unionid"] = $user_info["unionid"] ?? '';
  361. $params['platform'] = User::PLATFORM_WECHAT;
  362. $params['platform_data'] = $user_info;
  363. $result = self::checkIsAuthorized($params);
  364. $return_data['openid'] = $user_info["openid"];
  365. if (empty($result)) throw new Exception(self::getStaticError());
  366. if (!empty($result['user'])) {
  367. $user = $result['user'];
  368. \Yii::$app->user->login($user);
  369. $res = \Yii::$app->services->apiAccessToken->getAccessToken($user, 'api');
  370. $return_data['access_token'] = $res['access_token'];
  371. // 触发登录成功事件,事务提交完成后触发
  372. $event = new UserLoginEvent($user['mall_id']);
  373. \Yii::$app->services->events->dispatch($event, [
  374. 'mall_id' => $user['mall_id'],
  375. 'nickname' => $user['nickname'],
  376. 'user_id' => $user['id'],
  377. 'platform' => $user['platform'],
  378. 'ip' => ArrayHelper::get_client_ip(),
  379. 'device_type' => $params['device_type'] ?? '',
  380. 'device_mac' => $params['device_mac'] ?? '',
  381. ], $event->listeners);
  382. }
  383. return $return_data;
  384. }
  385. return $return_data;
  386. } catch (\Exception $e) {
  387. \Yii::error("authorized error=" . $e->getFile() . ";line:" . $e->getLine() . ";message:" . $e->getMessage());
  388. self::$static_error = $e->getMessage();
  389. return false;
  390. }
  391. }
  392. /**
  393. * @desc:
  394. * @Author: hua
  395. * @Date: 2021/10/25
  396. * @Time: 16:40
  397. * @Copyright: copyright (c) 2021 广东七件事集团
  398. * @return array
  399. * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
  400. * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
  401. * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException
  402. * @throws \Psr\SimpleCache\InvalidArgumentException
  403. */
  404. public function getJsSdkConfig()
  405. {
  406. $app = \Yii::$app->wechat->getApp();
  407. $url = \Yii::$app->request->get('url');
  408. if ($url) {
  409. $app->jssdk->setUrl($url);
  410. }
  411. $res = $app->jssdk->buildConfig([
  412. 'chooseImage',
  413. 'onMenuShareTimeline',
  414. 'onMenuShareQQ',
  415. 'onMenuShareWeibo',
  416. 'onMenuShareQZone',
  417. 'updateAppMessageShareData',
  418. 'stopRecord',
  419. 'scanQRCode',
  420. 'chooseWXPay',
  421. 'getLocation',
  422. 'updateTimelineShareData'
  423. ], $debug = false, $beta = false, $json = false);
  424. return ['config' => $res];
  425. }
  426. }