mall_id = $mall_id; $this->config = \Yii::$app->services->setting->mall->get($mall_id, 'alipay_mini'); $option = $this->getOptions(); Factory::setOptions($option); } private function getOptions() { $options = new Config(); $options->protocol = 'https'; $options->gatewayHost = 'openapi.alipay.com'; $options->signType = 'RSA2'; $options->appId = $this->config['app_id']; // 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中 $options->merchantPrivateKey = $this->config['merchantPrivateKey']; if ($this->config['is_use_cert']) { $options->alipayCertPath = dirname(Yii::$app->basePath).'/'.$this->config['alipayCertPath']; $options->alipayRootCertPath = dirname(Yii::$app->basePath).'/'.$this->config['alipayRootCertPath']; $options->merchantCertPath = dirname(Yii::$app->basePath).'/'.$this->config['merchantCertPath']; } else { //注:如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可 $options->alipayPublicKey = file_get_contents(dirname(Yii::$app->basePath).'/'.$this->config['alipayCertPath']); } //可设置异步通知接收服务地址(可选) $options->notifyUrl = ''; //可设置AES密钥,调用AES加解密相关接口时需要(可选) $options->encryptKey = $this->config['encryptKey']; return $options; } /** * * @param $code * @throws \Exception * @return array|bool */ public function authorize($code, $parent_id){ $option = $this->getOptions(); Yii::error('authorize option:'.json_encode($option)); Factory::setOptions($option); try { $result = Factory::base()->oauth()->getToken($code); Yii::error('authorize result:'.json_encode($result)); $responseChecker = new ResponseChecker(); //3. 处理响应或异常 if (!$responseChecker->success($result)) { $this->setError($result->msg.",".$result->subMsg); return false; } $return_data['openid'] = $result->userId; //支付宝的会员ID $return_data['access_token'] = ''; //支付宝用户id $user_info = $this->checkIsAuthorized($result->userId); if(!$user_info){ if(!$result->accessToken) throw new Exception('授权失败'); $user_info = $this->getUserInfoShare($result->accessToken, $parent_id); if (empty($user_info)) { $this->setError($this->getError()); return false; } } if($user_info){ if($user_info['user_id'] > 0){ //支付宝的会员ID已存在用户表中 $user = \common\models\user\User::findOne($user_info['user_id']); \Yii::$app->user->login($user); $res = \Yii::$app->services->apiAccessToken->getAccessToken($user, 'api'); $return_data['access_token'] = $res['access_token']; // 触发登录成功事件,事务提交完成后触发 $event = new UserLoginEvent($user['mall_id']); \Yii::$app->services->events->dispatch($event, ['mall_id' => $user['mall_id'], 'nickname' => $user['nickname'], 'user_id' => $user['id'], 'platform' =>$user['platform'], 'ip' => ArrayHelper::get_client_ip()], $event->listeners); } } return $return_data; } catch (Exception $e) { $this->setError('请求失败:'.$e->getMessage()); return false; } } /** * 通过token获取支付宝会员信息 * @param $token * @return array|bool|mixed|void * @throws \yii\base\Exception * @throws \yii\db\Exception */ public function getUserInfoShare($token, $parent_id) { //设置系统参数(OpenAPI中非biz_content里的参数) $textParams = array( 'auth_token' => $token ); //设置业务参数(OpenAPI中biz_content里的参数) $extendParams =[]; $bizParams = []; $result = Factory::util()->generic()->execute("alipay.user.info.share",$textParams, $bizParams); $responseChecker = new ResponseChecker(); //3. 处理响应或异常 if (!$responseChecker->success($result)) { $this->setError($result->msg.",".$result->subMsg); return false; } Yii::error('httpBody:'.$result->httpBody); $bodyJson = json_decode($result->httpBody, true); $user_info = []; if($bodyJson['alipay_user_info_share_response']){ //avatar nick_name user_id 暂时没看到mobile $platform_data = $bodyJson['alipay_user_info_share_response']; $model = UserInfo::setData([ 'user_id' => 0, 'unionid' => '', 'openid' => $bodyJson['alipay_user_info_share_response']['user_id'] ?? 0, 'platform' => \common\models\user\User::PLATFORM_MP_ALI, 'mall_id' => $this->mall_id, 'platform_data' => $bodyJson['alipay_user_info_share_response'] ]); if(!$model) throw new Exception(UserInfo::getStaticError()); $user_info_id = $model->id; //后台设置支付宝小程序是否有授权手机号的能力 $can_auth_phone = $this->config['can_auth_phone'] ?? false; if(!$can_auth_phone){ //直接注册用户 $password = StringHelper::random(6,true); $params['password'] = \Yii::$app->getSecurity()->generatePasswordHash($password); $params["username"] = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : ''; $params["openid"] = $platform_data["user_id"]; //支付宝open_id $params["unionid"] = ''; $params["nickname"] = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : ''; $params["headimgurl"] = $platform_data["avatar"] ?? ''; $params["avatar_url"] = $platform_data["avatar"] ?? ''; $params['platform'] = \common\models\user\User::PLATFORM_MP_ALI; $params['last_login_at'] = time(); $params['mall_id'] = $this->mall_id; $params['parent_id'] = $parent_id ?? 0; // 直推人 $user = \common\models\user\User::setData($params); if ($user == false) throw new Exception(User::getStaticError()); // 小程序授权手机触发注册事件 $event = new UserRegisterEvent($params['mall_id']); $data = ['user_id' => $user->id, 'platform' => $user->platform]; \Yii::$app->services->events->dispatch($event, $data, $event->listeners); if(!UserInfo::updateAll(['user_id' => $user->id ],['id' => $user_info_id])) throw new Exception('update error'); // $model->user_id = $user->id; // $res = $model->save(); // if ($res == false) throw new Exception(UserInfo::getStaticError()); } $user_info = UserInfo::getOne([['id' => $model->id]],true); } return $user_info; } /** * @desc:授权 * @Author: hua * @Date: 2021/10/25 * @Time: 11:21 * @Copyright: copyright (c) 2021 广东七件事集团 * @param $params * @return array|false */ public function checkIsAuthorized($alipay_user_id,$is_array = true) { $where = [['mall_id' => $this->mall_id], ['status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]]; $where[] = ['openid' => $alipay_user_id]; $where[] = ['platform' => \common\models\user\User::PLATFORM_MP_ALI]; $user_info = UserInfo::getOne($where,$is_array); return $user_info; } /** * 支付宝encryptedData 解密 * @param $encryptedData * @return false|void * @throws */ public function decryptData($encryptedData) { Yii::error('$encryptedData:'.$encryptedData); $result = Factory::util()->aes()->decrypt($encryptedData); Yii::error('decryptData:'.$result); $result = json_decode($result); $responseChecker = new ResponseChecker(); //3. 处理响应或异常 if (!$responseChecker->success($result)) { $this->setError($result->msg,",".$result->subMsg); return false; } if(!$result->mobile){ $this->setError('支付宝小程序权限:获取不到会员手机号'); return false; } $mobile = $result->mobile; return $mobile; } public function authorizedMobilePhone($params) { try{ $mobile = $this->decryptData($params['encryptData']); if(!$mobile){ throw new Exception($this->getError()); } $where = [['mobile' => $mobile], ['mall_id' => $this->mall_id], ['status' => [StatusEnum::DISABLED, StatusEnum::ENABLED]]]; $user = \common\models\user\User::getOne($where); $user_info = $this->checkIsAuthorized($params['openid'],false); $platform_data = json_decode($user_info->platform_data, true); if (!empty($user)) { $res = UserInfo::findOne(['mall_id' => $this->mall_id, 'user_id' => $user->id,'platform'=>$user_info->platform,'status'=>StatusEnum::ENABLED]); if (!empty($res)) throw new \yii\db\Exception('该手机号码已经被注册'); $user_info->user_id = $user->id; $res = $user_info->save(); if ($res == false) throw new Exception(UserInfo::getStaticError()); $user->nickname = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : ''; $user->avatar_url = $platform_data['avatar'] ?? ''; $user->platform = $user_info->platform; $res = $user->save(); if ($res == false) throw new Exception(\common\models\user\User::getStaticError()); }else{ if($user_info && $user_info->user_id > 0){ //存在用户,直接修改用户的手机号 $user = \common\models\user\User::findOne(['id' => $user_info->user_id]); $user->mobile = $mobile; $user->nickname = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : ''; $user->avatar_url = $platform_data['avatar'] ?? ''; $user->platform = $user_info->platform; $res = $user->save(); if ($res == false) throw new Exception('手机号修改失败'); }else{ $password = substr($mobile,-6,6); $params['password'] = \Yii::$app->getSecurity()->generatePasswordHash($password); $params["username"] = $mobile; $params["openid"] = $platform_data["user_id"]; $params["unionid"] = $platform_data["unionid"] ?? ''; $params["nickname"] = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : ''; $params["headimgurl"] = $platform_data["avatar"] ?? ''; $params["avatar_url"] = $platform_data["avatar"] ?? ''; $params['platform'] = $user_info->platform; $params['last_login_at'] = time(); $params['mall_id'] = $this->mall_id; $params['mobile'] = $mobile; $user = \common\models\user\User::setData($params); if ($user == false) throw new \yii\db\Exception(User::getStaticError()); $user_info->user_id = $user->id; $res = $user_info->save(); if ($res == false) throw new Exception(UserInfo::getStaticError()); } // 小程序授权手机触发注册事件 $event = new UserRegisterEvent($this->mall_id); $data = ['user_id' => $user->id, 'platform' => $user->platform]; \Yii::$app->services->events->dispatch($event, $data, $event->listeners); } \Yii::$app->user->login($user); // 触发登录成功事件,事务提交完成后触发 $event = new UserLoginEvent($user->mall_id); \Yii::$app->services->events->dispatch($event, ['mall_id' => $user->mall_id, 'nickname' => $user->nickname, 'user_id' => $user->id, 'platform' => $user->platform, 'ip' => ArrayHelper::get_client_ip()], $event->listeners); return \Yii::$app->services->apiAccessToken->getAccessToken($user, 'api'); }catch(Exception $e){ $this->setError($e->getMessage()); Yii::error('authorizedMobilePhone error:'.$e->getMessage()); return false; } } /** * 获取小程序二维码链接 * @param $url * @param $query * @param $desc * @return bool|string * @throws Exception */ public function qrcode($url,$query,$desc) { $desc = $desc ?: '海报分享'; $result = Factory::base()->qrcode()->create($url,$query,$desc); $responseChecker = new ResponseChecker(); //3. 处理响应或异常 if (!$responseChecker->success($result)) { \Yii::error($result->msg.",".$result->subMsg); $this->setError($result->msg.",".$result->subMsg); return false; } return $result->qrCodeUrl; } public function bindMobileBySms($openid,$mobile,$captcha) { try{ //手机验证码验证 if (YII_ENV == 'prod') { //短信验证码 if (!Sms::checkValidateCode($mobile, $captcha,Sms::SMS_TYPE_MOBILE_BIND)) throw new \Exception('验证码不正确'); } //查询user_info $user_info = $this->checkIsAuthorized($openid,false); if(!$user_info) throw new Exception('查询不到授权信息'); $where = [['mobile' => $mobile], ['mall_id' => $this->mall_id], ['status' => [StatusEnum::DISABLED, StatusEnum::ENABLED]]]; $user = \common\models\user\User::getOne($where); $user_info = $this->checkIsAuthorized($openid,false); $platform_data = json_decode($user_info->platform_data, true); if (!empty($user)) { $res = UserInfo::findOne(['mall_id' => $this->mall_id, 'user_id' => $user->id, 'platform' => $user_info->platform, 'status' => StatusEnum::ENABLED]); if (!empty($res)) throw new \Exception('该手机号码已经被注册'); $user_info->user_id = $user->id; $res = $user_info->save(); if ($res == false) throw new Exception(UserInfo::getStaticError()); $user->nickname = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : ''; $user->avatar_url = $platform_data['avatar'] ?? ''; $user->platform = $user_info->platform; $res = $user->save(); if ($res == false) throw new Exception(\common\models\user\User::getStaticError()); }else{ if($user_info->user_id > 0){ //查询对应用户信息 $user = User::find()->where(['id' => $user_info->user_id,'mall_id' => $this->mall_id,'status' => StatusEnum::ENABLED])->one(); if($user->mobile) throw new Exception('该用户已绑定手机号'); $user->mobile = $mobile; $user->platform = $user_info->platform; $res = $user->save(); if (!$res) throw new Exception('手机号修改失败'); }else{ $platform_data = json_decode($user_info->platform_data, true); $password = substr($mobile,-6,6); $params['password'] = \Yii::$app->getSecurity()->generatePasswordHash($password); $params["username"] = $mobile; $params["openid"] = $platform_data["user_id"]; $params["unionid"] = $platform_data["unionid"] ?? ''; $params["nickname"] = $platform_data['nick_name'] ? (string)$platform_data['nick_name'] : ''; $params["headimgurl"] = $platform_data["avatar"] ?? ''; $params["avatar_url"] = $platform_data["avatar"] ?? ''; $params['platform'] = $user_info->platform; $params['last_login_at'] = time(); $params['mall_id'] = $this->mall_id; $params['mobile'] = $mobile; $user = \common\models\user\User::setData($params); if (!$user) throw new \Exception(\common\models\base\User::getStaticError()); $user_info->user_id = $user->id; $res = $user_info->save(); if (!$res) throw new Exception(UserInfo::getStaticError()); // 小程序授权手机触发注册事件 $event = new UserRegisterEvent($this->mall_id); $data = ['user_id' => $user->id, 'platform' => $user->platform]; \Yii::$app->services->events->dispatch($event, $data, $event->listeners); } } //支付宝的会员ID已存在用户表中 $user = \common\models\user\User::findOne($user_info->user_id); \Yii::$app->user->login($user); $res = \Yii::$app->services->apiAccessToken->getAccessToken($user, 'api'); $return_data['access_token'] = $res['access_token']; // 触发登录成功事件,事务提交完成后触发 $event = new UserLoginEvent($user['mall_id']); \Yii::$app->services->events->dispatch($event, ['mall_id' => $user['mall_id'], 'nickname' => $user['nickname'], 'user_id' => $user['id'], 'platform' =>$user['platform'], 'ip' => ArrayHelper::get_client_ip()], $event->listeners); return $return_data; }catch (Exception $e){ $this->setError($e->getMessage()); return false; } } }