From 4cbd1414161de101ec7a2c1313dcc443e8b240ea Mon Sep 17 00:00:00 2001 From: JaguarJack <82664165@qq.com> Date: Sat, 26 Jan 2019 18:04:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=A4=BE=E4=BC=9A=E5=8C=96?= =?UTF-8?q?=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/cloud.php | 7 + extend/.gitignore | 2 - extend/socialite/command/SocialiteCommand.php | 30 ++++ extend/socialite/composer.json | 17 ++ extend/socialite/config/socialite.php | 35 ++++ extend/socialite/src/Socialite.php | 110 ++++++++++++ extend/socialite/src/User.php | 165 +++++++++++++++++ extend/socialite/src/contract/Provider.php | 14 ++ extend/socialite/src/facade/Socialite.php | 24 +++ .../src/provider/AbstractProvider.php | 170 ++++++++++++++++++ .../socialite/src/provider/GithubProvider.php | 68 +++++++ extend/socialite/src/provider/QqProvider.php | 100 +++++++++++ .../socialite/src/provider/WeiBoProvider.php | 87 +++++++++ extend/socialite/src/provider/WxProvider.php | 101 +++++++++++ 14 files changed, 928 insertions(+), 2 deletions(-) create mode 100644 config/cloud.php delete mode 100644 extend/.gitignore create mode 100644 extend/socialite/command/SocialiteCommand.php create mode 100644 extend/socialite/composer.json create mode 100644 extend/socialite/config/socialite.php create mode 100644 extend/socialite/src/Socialite.php create mode 100644 extend/socialite/src/User.php create mode 100644 extend/socialite/src/contract/Provider.php create mode 100644 extend/socialite/src/facade/Socialite.php create mode 100644 extend/socialite/src/provider/AbstractProvider.php create mode 100644 extend/socialite/src/provider/GithubProvider.php create mode 100644 extend/socialite/src/provider/QqProvider.php create mode 100644 extend/socialite/src/provider/WeiBoProvider.php create mode 100644 extend/socialite/src/provider/WxProvider.php diff --git a/config/cloud.php b/config/cloud.php new file mode 100644 index 0000000..c205360 --- /dev/null +++ b/config/cloud.php @@ -0,0 +1,7 @@ +setName('socialite publish') + ->setDescription('publish socialite config'); + } + + protected function execute(Input $input, Output $output) + { + $config = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'socialite.php'; + + copy($config, app('config_path')); + + $output->writeln('publish successfully, check it' . PHP_EOL); + } +} \ No newline at end of file diff --git a/extend/socialite/composer.json b/extend/socialite/composer.json new file mode 100644 index 0000000..cf223fd --- /dev/null +++ b/extend/socialite/composer.json @@ -0,0 +1,17 @@ +{ + "name": "thinking/socialite", + "description": "a socialite package for thinkphp5.1*", + "license": "MIT", + "authors": [ + { + "name": "yanwnewu", + "email": "82664165@qq.com" + } + ], + "minimum-stability": "dev", + "require": { + "php": "^7.1.3", + "ext-json": "*", + "guzzlehttp/guzzle": "~6.0" + } +} diff --git a/extend/socialite/config/socialite.php b/extend/socialite/config/socialite.php new file mode 100644 index 0000000..1a96036 --- /dev/null +++ b/extend/socialite/config/socialite.php @@ -0,0 +1,35 @@ + 'qq', + + 'qq' => [ + 'app_id' => '101540418', + 'app_secret' => 'fae33241fa62f8b375565365e216cde7', + 'redirect_url' => 'http://127.0.0.1:8000/oauth', + ], + + 'weibo' => [ + 'app_id' => '2539916570', + 'app_secret' => 'aae0e36c96ecc04f873be3e0dc06f71b', + 'redirect_url' => 'http://www.rllady.com/home/index/sinaLogin', + ], + + 'github' => [ + 'app_id' => '5b8a9a7e8dded81c128d', + 'app_secret' => '12657a874d3c036a5b9e55c7512ffd5292e67118', + 'redirect_url' => 'http://127.0.0.1:8000/oauth', + ], + + 'wx' => [ + 'app_id' => 'wx83f3fcd9e0cfdff8', + 'app_secret' => '2a736290f3af0fb40710a65c938b40b3', + 'redirect_url' => 'http://127.0.0.1:8000/oauth', + 'scope' => 'snsapi_login', + ], +]; \ No newline at end of file diff --git a/extend/socialite/src/Socialite.php b/extend/socialite/src/Socialite.php new file mode 100644 index 0000000..b7b1ed7 --- /dev/null +++ b/extend/socialite/src/Socialite.php @@ -0,0 +1,110 @@ +createDriver($type); + + $driver->oauth(); + + return $driver; + } + + /** + * create oauth provider + * + * @time at 2018年12月29日 + * @param $type + * @return mixed + */ + protected function createDriver($type) + { + $defaultDriver = config('socialite.default'); + + $driver = $type ? : $defaultDriver; + + $function = $driver . 'Driver'; + + return call_user_func([$this, $function]); + } +} \ No newline at end of file diff --git a/extend/socialite/src/User.php b/extend/socialite/src/User.php new file mode 100644 index 0000000..2a1d871 --- /dev/null +++ b/extend/socialite/src/User.php @@ -0,0 +1,165 @@ +id; + } + + /** + * get nickname + * + * @time at 2018年12月29日 + * @return string + */ + public function getNickName() + { + return $this->nickname; + } + + /** + * get email + * + * @time at 2018年12月29日 + * @return string + */ + public function getEmail() + { + return $this->email; + } + + /** + * get avatar + * + * @time at 2018年12月29日 + * @return string + */ + public function getAvatar() + { + return $this->avatar; + } + + /** + * get name + * + * @time at 2018年12月29日 + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * set user + * + * @time at 2018年12月29日 + * @param $user + * @return $this + */ + public function setUser($user) + { + $this->user = $user; + + return $this; + } + + /** + * set property + * + * @time at 2018年12月29日 + * @param $user + * @return $this + */ + public function map($user) + { + foreach ($user as $attr => $value) { + if ($this->hasProperty($attr)) { + $this->{$attr} = $value; + } + } + + return $this; + } + + /** + * has property + * + * @time at 2018年12月29日 + * @param $attr + * @return bool + */ + protected function hasProperty($attr) + { + return property_exists($this, $attr); + } + + public function __get($name) + { + // TODO: Implement __get() method. + return $this->user[$name]; + } + + public function __isset($name) + { + // TODO: Implement __isset() method. + return isset($this->user[$name]); + } + + public function __set($name, $value) + { + // TODO: Implement __set() method. + $this->user[$name] = $value; + } + + public function __unset($name) + { + // TODO: Implement __unset() method. + unset($this->user[$name]); + } + +} \ No newline at end of file diff --git a/extend/socialite/src/contract/Provider.php b/extend/socialite/src/contract/Provider.php new file mode 100644 index 0000000..dea0eaa --- /dev/null +++ b/extend/socialite/src/contract/Provider.php @@ -0,0 +1,14 @@ +appId = $appId; + $this->appSecret = $appSecret; + $this->redirectUrl = $redirectUrl; + $this->scope = $scope; + $this->request = app('request'); + } + + protected function getHttpClient() + { + if (is_null($this->httpClient)) { + $this->httpClient = new Client(); + } + return $this->httpClient; + } + + /** + * oauth login + * + * @time at 2018年12月29日 + * @return void + */ + public function oauth() + { + if (!$this->request->get('code')) { + throw new HttpResponseException(redirect($this->authorizeUrl . '?' . http_build_query($this->createOauthParams()))); + } + } + + /** + * create oauth params + * + * @time at 2018年12月29日 + * @return array + */ + protected function createOauthParams() + { + return [ + 'response_type' => 'code', + $this->clientIdKey => $this->appId, + 'redirect_uri' => $this->redirectUrl, + 'scope' => $this->getScope(), + 'state' => $this->state(), + ]; + } + + /** + * set scope + * + * @time at 2018年12月29日 + * @param $scope + * @return $this + */ + public function setScope($scope) + { + $this->scope = $scope; + + return $this; + } + + /** + * get scope + * + * @time at 2018年12月29日 + * @return string + */ + protected function getScope() + { + return is_array($this->scope) ? trim(implode($this->scope), ',') : $this->scope; + } + + /** + * get state + * + * @time at 2018年12月29日 + * @return mixed + */ + protected function getState() + { + $state = $this->request->session('state'); + + $this->request->session('state', null); + + return $state; + } + + /** + * check state + * + * @time at 2018年12月29日 + * @return void + */ + protected function checkState() + { + if ($this->request->param('state') != $this->getState()) { + throw new HttpException(401, 'Authorized login State verification failed, Please check it'); + } + } + + /** + * generate state + * + * @time at 2018年12月29日 + * @return string + */ + protected function state() + { + $state = md5(rand(1,100000)); + + Session::set('state', $state); + + return $state; + } + + /** + * get token params + * + * @time at 2018年12月29日 + * @return array + */ + protected function getTokenParams() + { + $this->checkState(); + + return [ + 'code' => $this->request->get('code'), + 'client_secret' => $this->appSecret, + $this->clientIdKey => $this->appId, + 'redirect_uri' => $this->redirectUrl, + ]; + } + + protected function getPostKey() + { + return (version_compare(ClientInterface::VERSION, '6') === 1) ? 'form_params' : 'body'; + } +} \ No newline at end of file diff --git a/extend/socialite/src/provider/GithubProvider.php b/extend/socialite/src/provider/GithubProvider.php new file mode 100644 index 0000000..724180c --- /dev/null +++ b/extend/socialite/src/provider/GithubProvider.php @@ -0,0 +1,68 @@ +getHttpClient()->post($this->accessTokenUrl, [ + 'verify' => false, + 'headers' => ['Accept' => 'application/json'], + $this->getPostKey() => array_merge($this->getTokenParams()) + ]); + + $token = json_decode($response->getBody()->getContents(), true); + + if (!isset($token['access_token'])) { + throw new HttpException(401, 'Access Token Missing, Please ReLogin'); + } + + return $token['access_token']; + } + + + /** + * 获取用户信息 + * + * @time at 2018年12月28日 + * @return mixed + */ + public function user() + { + $response = $this->getHttpClient()->get($this->userUrl,[ + 'verify' => false, + 'headers' => ['Authorization' => sprintf('token %s', $this->getAccessToken())] + ]); + + $user = json_decode($response->getBody(), true); + + return (new User)->setUser($user)->map([ + 'id' => $user['id'], + 'nickname' => $user['login'], + 'name' => $user['name'], + 'email' => $user['email'], + 'avatar' => $user['avatar_url'], + ]); + } +} \ No newline at end of file diff --git a/extend/socialite/src/provider/QqProvider.php b/extend/socialite/src/provider/QqProvider.php new file mode 100644 index 0000000..e22b2be --- /dev/null +++ b/extend/socialite/src/provider/QqProvider.php @@ -0,0 +1,100 @@ +getHttpClient()->get($this->accessTokenUrl, [ + 'verify' => false, + 'query' => array_merge($this->getTokenParams(), ['grant_type' => 'authorization_code']) + ]); + + parse_str($response->getBody()->getContents(), $token); + + if (!isset($token['access_token'])) { + throw new HttpException(401, 'Access Token Missing, Please ReLogin'); + } + return $token['access_token']; + } + + /** + * 获取 Open ID + * + * @time at 2018年12月28日 + * @return array + */ + protected function getOpenId() + { + $accessToken = $this->getAccessToken(); + + $response = $this->getHttpClient()->get($this->openIdUrl, [ + 'verify' => false, + 'query' => ['access_token' => $accessToken] + ]); + + $openidStr = (string)$response->getBody()->getContents(); + + $openIdArr = json_decode(substr($openidStr,strpos($openidStr,'(')+1,-3),true); + + return array_merge($openIdArr, ['access_token' => $accessToken]); + } + + /** + * 获取用户信息 + * + * @time at 2018年12月28日 + * @return mixed + */ + public function user() + { + $getUserParams = $this->getOpenId(); + + unset($getUserParams['app_id']); + $getUserParams['oauth_consumer_key'] = $this->appId; + + $response = $this->getHttpClient()->get($this->userUrl, [ + 'verify' => false, + 'headers' => ['Accept' => 'application/json'], + 'query' => $getUserParams, + ]); + + $user = json_decode($response->getBody()->getContents(), true); + + $user['open_id'] = $getUserParams['openid']; + + return (new User)->setUser($user)->map([ + 'id' => $getUserParams['openid'], + 'nickname' => $user['nickname'], + 'avatar' => $user['figureurl_2'], + ]); + + } + +} \ No newline at end of file diff --git a/extend/socialite/src/provider/WeiBoProvider.php b/extend/socialite/src/provider/WeiBoProvider.php new file mode 100644 index 0000000..d48c9a0 --- /dev/null +++ b/extend/socialite/src/provider/WeiBoProvider.php @@ -0,0 +1,87 @@ +getHttpClient()->post($this->accessTokenUrl, [ + 'verify' => false, + $this->getPostKey() => array_merge($this->getTokenParams(), ['grant_type' => 'authorization_code']) + ]); + + $token = json_decode($response->getBody()->getContents(), true); + + if (!isset($token['access_token'])) { + throw new HttpException(401, 'Access Token Missing, Please ReLogin'); + } + + return $token['access_token']; + } + + /** + * 获取 Open ID + * + * @time at 2018年12月28日 + * @return array + */ + protected function getTokenInfo() + { + $accessToken = $this->getAccessToken(); + + $response = $this->getHttpClient()->post($this->tokenInfoUrl, [ + 'verify' => false, + $this->getPostKey() => ['access_token' => $accessToken] + ]); + + $tokenInfo = json_decode($response->getBody()->getContents(), true); + + return ['access_token' => $accessToken, 'uid' => $tokenInfo['uid']]; + } + + /** + * 获取用户信息 + * + * @time at 2018年12月28日 + * @return mixed + */ + public function user() + { + $response = $this->getHttpClient()->get($this->userUrl,[ + 'verify' => false, + 'query' => $this->getTokenInfo(), + ]); + + $user = json_decode($response->getBody(), true); + + return (new User)->setUser($user)->map([ + 'id' => $user['idstr'], + 'nickname' => $user['name'], + 'avatar' => $user['profile_image_url'], + ]); + } +} \ No newline at end of file diff --git a/extend/socialite/src/provider/WxProvider.php b/extend/socialite/src/provider/WxProvider.php new file mode 100644 index 0000000..1f4ac02 --- /dev/null +++ b/extend/socialite/src/provider/WxProvider.php @@ -0,0 +1,101 @@ +getHttpClient()->get($this->accessTokenUrl, [ + 'verify' => false, + 'query' => array_merge($this->getTokenParams(), ['grant_type' => 'authorization_code']) + ]); + + parse_str($response->getBody()->getContents(), $token); + + if (!isset($token['access_token'])) { + throw new HttpException(401, 'Access Token Missing, Please ReLogin'); + } + return $token['access_token']; + } + + /** + * 获取 Open ID + * + * @time at 2018年12月28日 + * @return array + */ + protected function getOpenId() + { + $accessToken = $this->getAccessToken(); + + $response = $this->getHttpClient()->get($this->openIdUrl, [ + 'verify' => false, + 'query' => ['access_token' => $accessToken] + ]); + + $openidStr = (string)$response->getBody()->getContents(); + + $openIdArr = json_decode(substr($openidStr,strpos($openidStr,'(')+1,-3),true); + + return array_merge($openIdArr, ['access_token' => $accessToken]); + } + + /** + * 获取用户信息 + * + * @time at 2018年12月28日 + * @return mixed + */ + public function user() + { + $getUserParams = $this->getOpenId(); + + unset($getUserParams['app_id']); + $getUserParams['oauth_consumer_key'] = $this->appId; + + $response = $this->getHttpClient()->get($this->userUrl, [ + 'verify' => false, + 'headers' => ['Accept' => 'application/json'], + 'query' => $getUserParams, + ]); + + $user = json_decode($response->getBody()->getContents(), true); + + $user['open_id'] = $getUserParams['openid']; + + return (new User)->setUser($user)->map([ + 'id' => $getUserParams['openid'], + 'nickname' => $user['nickname'], + 'avatar' => $user['figureurl_2'], + ]); + + } + +} \ No newline at end of file