user) { return false; } return true; } /** * 登录凭证校验 * @param $code * @param $iv * @param $encryptedData * @return array * @throws \fast\FuncException */ public function code2session($code, $iv, $encryptedData) { $http = new Http(); $url = "https://api.weixin.qq.com/sns/jscode2session?appid=" . env("app.appid") . "&secret=" . env("app.appsecret") . "&js_code={$code}&grant_type=authorization_code"; $res = $http::get($url); if ($res['code'] != 200) { throw new \fast\FuncException($res['msg']); } $res['data'] = json_decode($res['data'], true); if (isset($res['data']['errcode'])) { throw new \fast\FuncException($res['data']['errmsg']); } session('app_openid', $res['data']['openid']); session('app_session_key', $res['data']['session_key']); $res['userInfo'] = json_decode($this->decodeWechatIv($iv, $encryptedData), true); $result = []; $result['openid'] = $res['data']['openid']; if (isset($res['data']['unionid'])) $result['unionid'] = $res['data']['unionid']; $result['phone'] = $res['userInfo']['phoneNumber']; return $result; } /** * 解密微信的iv和encryptedData * @param $iv * @param $encryptedData * @return false|string * @throws \fast\FuncException */ public function decodeWechatIv($iv, $encryptedData) { $openid = session('app_openid'); $session_key = session('app_session_key'); if (!$openid || !$session_key) { throw new \fast\FuncException('缺少主要参数'); } if (strlen($session_key) != 24) { throw new \fast\FuncException('sessionkey长度错误'); } if (strlen($iv) != 24) { throw new \fast\FuncException('iv长度错误'); } $aesKey = base64_decode($session_key); $aesIV = base64_decode($iv); $aesCipher = base64_decode($encryptedData); $result = openssl_decrypt($aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV); $dataObj = json_decode($result); if ($dataObj == NULL) { throw new \fast\FuncException('登录失败,请稍候再试'); } if ($dataObj->watermark->appid != env("app.appid")) { throw new \fast\FuncException('小程序appid不一致,登录失败'); } return $result; } /** * 用户端登录 * @param $phone * @param $openid * @param $unionid * @return WechatUser|mixed * @throws \fast\FuncException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function userLogin($phone, $openid, $unionid) { $field = 'id,openid,phone,nickname,sex,headimgurl'; $user = WechatUser::where('phone', $phone)->where('delete_time', 0)->field($field)->find(); if ($openid != $user->openid) { WechatUser::where('id', $user->id)->save(['openid' => $user->openid]); } if ($user) { return $this->userSuccess($user); } return $this->register($phone, $openid, $unionid); } /** * * @param $phone * @return WechatUser|array|mixed * @throws \fast\FuncException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function userPhoneLogin($phone) { $field = 'id,openid,phone,nickname,sex,headimgurl'; $user = WechatUser::where('phone', $phone)->where('delete_time', 0)->field($field)->find(); if ($user) { return $this->userSuccess($user); } return $this->register($phone); } /** * 用户登录成功 * @param WechatUser $user * @return array */ public function userSuccess(WechatUser $user) { session('user', $user->toArray()); $this->userKeeplogin($user->id,$user->openid,3600 * 24 * 7); // $user->visible(['id', 'name', 'logo']); return $user->toArray(); } /** * 保持登录 * @param $user_id * @param $token * @param $keeptime * @return bool */ protected function userKeeplogin($user_id, $token, $keeptime = 0) { if ($keeptime) { $expiretime = time() + $keeptime; $key = md5(md5(strval($user_id)) . md5(strval($keeptime)) . md5(strval($expiretime)) . $token); error_reporting(E_ALL); ini_set('display_errors', '1'); $data = [$user_id, $keeptime, $expiretime, $key]; Cookie::set('userKeeplogin', implode('|', $data), 86400 * 30); return true; } return false; } /** * 用户端注册 * @param $phone * @param string $openid * @param string $unionid * @return WechatUser|mixed * @throws \fast\FuncException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function register($phone, string $openid = '', string $unionid = '') { $add = [ 'phone' => $phone, 'openid' => $openid, 'nickname' => '微信用户', 'unionid' => $unionid ?? '', ]; $id = (new WechatUser())->insertGetId($add); if (!$id) { throw new \fast\FuncException('注册失败,请稍候再试'); } $user = WechatUser::where('id', $id)->find(); return $this->userSuccess($user); } /** * 自动登录 * @return WechatUser|array|false|mixed|\think\Model * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function userAutologin() { $keeplogin = Cookie::get('userKeeplogin'); if (!$keeplogin) { return false; } [$id, $keeptime, $expiretime, $key] = explode('|', $keeplogin); if ($id && $keeptime && $expiretime && $key && $expiretime > time()) { $user = WechatUser::where('id', $id)->find(); if (!$user || !$user->token) { return false; } unset($user->password); //token有变更 if ($key != md5(md5($id) . md5($keeptime) . md5($expiretime) . $user->token)) { return false; } Session::set('user', $user->toArray()); //刷新自动登录的时效 $this->userKeeplogin($id,$user->token,$keeptime); return $user; } else { return false; } } /** * 登出 * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function userLogout() { $user = WechatUser::find($this->user_id); if ($user) { $user->token = ''; $user->save(); } Session::delete('user'); Cookie::delete('userKeeplogin'); return true; } }