diff --git a/modules/api/controllers/AuthController.php b/modules/api/controllers/AuthController.php index 5df5322..1aa5806 100644 --- a/modules/api/controllers/AuthController.php +++ b/modules/api/controllers/AuthController.php @@ -150,8 +150,47 @@ class AuthController extends Controller $data = $form->login(); $this->lock->release(); return $this->responseHandler($data); - } - + } + + + + /** + * showdoc + * @catalog 登录注册 + * @title 微信小程序登录 + * @description 本接口提供微信登录 + * @method post + * @url /api/auth/login-by-wxoa + * @param code 必选 string wx.login() 获取 临时登录凭证code + * @return {"code":0,"msg":"ok","data":{"access_token":"WXl0dXlzbDhxcTdTcExyQUVmVWRoLzV6cnJrK04rV1RocHVpTzdGTWxRajhLVzA3Vk9hWEhBPT0=","refresh_token":"aDcxQTc4ZDFtUGlWOEh6akUwaVVQQ2NuZGNxdTJhcDQ5cGxSZll6Mk9PWUJPdmhRQU1RMW5DWDl1SFllVFZrbWVvU1JCWEdOSUl2S29rU3I3NndobWVTN0kxNlhjSFhwODREYlRFUkFmZVhUNUpQZHkxd1oveWlnOVdQa2JzSHp6K1dZS1dtRVJBSzFwMnBnVnNmdncvRTgvWDRiSWhpUA==","access_token_expires":1592392165,"refresh_token_expires":1594976965}} + * @return_param access_token string 登录令牌 + * @return_param access_token_expires int 登录令牌失效时间 + * @return_param refresh_token string 刷新token令牌 + * @return_param refresh_token_expires int 刷新token令牌失效时间 + * @remark + */ + public function actionLoginByWxoa() + { + if(!\Yii::$app->request->isPost){ + $data = $this->invaildRequest(); + return $this->responseHandler($data); + } + if(!$this->lock->acquire()){ + $data = ['code' => 1, 'msg' => '系统繁忙!稍后再试^v^!']; + return $this->responseHandler($data); + } + $form = new LoginByWxmpForm(); + $form->attributes = \Yii::$app->request->post(); + $form->cx_mch_id = $this->cx_mch_id; + $form->token_type = $this->_cx_token_type; + $form->wechat_mp = $this->wechat_mp; + $data = $form->login(); + $this->lock->release(); + return $this->responseHandler($data); + } + + + /** * showdoc * @catalog 登录注册 diff --git a/modules/api/models/LoginByWxoaForm.php b/modules/api/models/LoginByWxoaForm.php new file mode 100644 index 0000000..c218928 --- /dev/null +++ b/modules/api/models/LoginByWxoaForm.php @@ -0,0 +1,215 @@ +validate()) { + return $this->getModelError(); + } + $res = FlashStorage::getCache("m{$this->cx_mch_id}_c{$this->code}"); + if ($this->code_expires == 1 || $res === false) { + $res = $this->code2session($this->code); + if ($res['code'] != 0) + return $res; + FlashStorage::setCache("m{$this->cx_mch_id}_c{$this->code}", $res, 864000); + } + + + $session_key = $res['data']['session_key']; + $openid = $res['data']['openid']; + $unionid = isset($res['data']['unionid']) ? $res['data']['unionid'] : null; + $res = $this->decrypted_data($session_key); + if ($res['code'] != 0) { + return $res; + } + $decrypted_info = json_decode($res['data'], true); + $openid = $openid ? $openid : $decrypted_info['openId']; + $nickname = $decrypted_info['nickName']; + $avatar_url = empty($decrypted_info['avatarUrl']) ? User::DEFAULT_AVATAR_URL : $decrypted_info['avatarUrl']; + $gender = $decrypted_info['gender']; + if ($unionid == null) { + $unionid = isset($decrypted_info['unionId']) ? $decrypted_info['unionId'] : '0'; + } + + //用户是否存在 + $user_oauth = null; + if ($unionid != 0) { + //优选使用unionid + $user_oauth = UserOauth::findOne([ + 'cx_mch_id' => $this->cx_mch_id, + 'is_delete' => 0, + 'unionid' => $unionid + ]); + } + if ($user_oauth == null) { + $user_oauth = UserOauth::findOne([ + 'cx_mch_id' => $this->cx_mch_id, + 'is_delete' => 0, + 'type' => SysConst::$cxOauthProviderWxmp, + 'openid' => $openid + ]); + } + + $t = \Yii::$app->db->beginTransaction(); + if ($user_oauth != null) { + //用户是否存在 + $user = User::findOne([ + 'id' => $user_oauth->user_id, + 'is_delete' => 0, + 'cx_mch_id' => $this->cx_mch_id, + 'status' => User::STATUS_NORMAL + ]); + if ($user == null) { + \Yii::error("[LoginByWxmpForm] 用户(ID:{$user_oauth->user_id})不存在"); + return [ + 'code' => 1, + 'msg' => '系统内部异常,请联系管理员' + ]; + } + } else { + $form = new CommonUserEditForm(); + $form->scenario = 'wxmp_signup'; + $form->model = new User(); + $form->cx_mch_id = $this->cx_mch_id; + $form->username = User::generateUsername(3, "wx", 6); + $form->nickname = $nickname; + $form->avatar_url = $avatar_url; + $form->access_token = \Yii::$app->security->generateRandomString(); + $form->gender = $gender; + $form->is_modify_un = 1; + $res = $form->save(); + if ($res['code'] != 0) + return $res; + + $user = $form->model; + + $user_oauth = new UserOauth(); + $user_oauth->cx_mch_id = $this->cx_mch_id; + $user_oauth->type = SysConst::$cxOauthProviderWxmp; + $user_oauth->user_id = $user->id; + $user_oauth->openid = $openid; + $user_oauth->unionid = $unionid; + $user_oauth->is_delete = 0; + $user_oauth->created_at = time(); + } + //更新用户信息 + $user_oauth->nickname = $nickname; + $user_oauth->avatar_url = $avatar_url; + if ($unionid !== 0 && $user_oauth->unionid == 0) { + $user_oauth->unionid = $unionid; + } + if (!$user_oauth->save()) { + $t->rollBack(); + return $this->getModelError($user_oauth); + } + if (!\Yii::$app->user->login($user)) { + $t->commit(); + return [ + 'code' => 1, + 'msg' => '登录失败' + ]; + } + $args = []; + $args['cx_mch_id'] = $this->cx_mch_id; + $args['token_type'] = $this->token_type; + $atoken = new AToken($args); + $data = $atoken->generate_access_token(); + if ($data['code'] == 0) { + $err_msg = "微信小程序登录成功"; + User::lastLogin($user->id, 1, $err_msg, $this->cx_mch_id); + } + $t->commit(); + //是否需要绑定 + $data = User::bindQuery($user_oauth->user, $data); + return $data; + } + + + /*** + * 用户数据解密 + */ + private function decrypted_data($session_key) + { + $pc = new WxBizDataCrypt($this->wechat_mp->appId, $session_key); + $errCode = $pc->decryptData($this->encrypted_data, $this->iv, $data); + if ($errCode == 0) { + return [ + 'code' => 0, + 'msg' => 'success', + 'data' => $data + ]; + } else { + return [ + 'code' => 1, + 'msg' => $errCode, + ]; + } + } + + private function code2session($code) + { + $api = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->wechat_mp->appId}&secret={$this->wechat_mp->appSecret}&code=" . $code . "&grant_type=authorization_code"; + $this->wechat_mp->curl->get($api); + if ($this->wechat_mp->curl->error_code != 0) { + return [ + 'code' => 1, + 'msg' => "err_code:{$this->wechat_mp->curl->error_code}err_msg:{$this->wechat_mp->curl->error_msg}" + ]; + } + $resp = $this->wechat_mp->curl->response; + $res = json_decode($resp, true); + if (!isset($res['access_token']) || !isset($res['openid'])) { + return [ + 'code' => 1, + 'msg' => isset($res['errmsg']) ? $res['errmsg'] : 'error' + ]; + } + return [ + 'code' => 0, + 'msg' => 'ok', + 'data' => $res + ]; + } +} \ No newline at end of file