├── .github └── FUNDING.yml ├── .gitignore ├── .php_cs ├── .travis.yml ├── LICENSE.txt ├── README.md ├── composer.json ├── phpunit.xml ├── src ├── AccessToken.php ├── AccessTokenInterface.php ├── AuthorizeFailedException.php ├── Config.php ├── FactoryInterface.php ├── HasAttributes.php ├── InvalidArgumentException.php ├── InvalidStateException.php ├── ProviderInterface.php ├── Providers │ ├── AbstractProvider.php │ ├── FacebookProvider.php │ ├── GitHubProvider.php │ ├── QQProvider.php │ ├── WeChatProvider.php │ └── WeiboProvider.php ├── SocialiteManager.php ├── User.php ├── UserInterface.php └── WeChatComponentInterface.php └── tests ├── HttpController └── Index.php └── index.php /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: overtrue 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | custom: # Replace with a single custom sponsorship URL 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store 5 | /.idea 6 | Thumbs.db 7 | /*.php 8 | sftp-config.json 9 | .php_cs.cache -------------------------------------------------------------------------------- /.php_cs: -------------------------------------------------------------------------------- 1 | 6 | 7 | This source file is subject to the MIT license that is bundled 8 | with this source code in the file LICENSE. 9 | EOF; 10 | 11 | return PhpCsFixer\Config::create() 12 | ->setRiskyAllowed(true) 13 | ->setRules(array( 14 | '@Symfony' => true, 15 | 'header_comment' => array('header' => $header), 16 | 'array_syntax' => array('syntax' => 'short'), 17 | 'ordered_imports' => true, 18 | 'no_useless_else' => true, 19 | 'no_useless_return' => true, 20 | 'php_unit_construct' => true, 21 | 'php_unit_strict' => true, 22 | )) 23 | ->setFinder( 24 | PhpCsFixer\Finder::create() 25 | ->exclude('vendor') 26 | ->in(__DIR__) 27 | ) 28 | ; -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.0 5 | - 7.1 6 | - 7.2 7 | 8 | sudo: false 9 | dist: trusty 10 | 11 | install: travis_retry composer install --no-interaction --prefer-source 12 | 13 | script: vendor/bin/phpunit --verbose 14 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) overtrue 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Socialite

2 |

3 | Build Status 4 | Latest Stable Version 5 | Latest Unstable Version 6 | Build Status 7 | Scrutinizer Code Quality 8 | Code Coverage 9 | Total Downloads 10 | License 11 |

12 | 13 | 14 |

基于 overtrue/socialite改造的,适用于easyswoole的第三方登录组件,现已支持wechat,qq,weibo,github,facebook

15 | 16 | # 依赖 17 | 18 | ``` 19 | PHP >= 7.0 20 | swoole >=4.4.0 21 | ``` 22 | # 安装 23 | 24 | ```shell 25 | $ composer require "xbing2002/socialite" "1.0" 26 | ``` 27 | 28 | # 使用说明 29 | 30 | 31 | `authorize.php`: 32 | 33 | ```php 34 | [ 40 | 'client_id' => 'your-app-id', 41 | 'client_secret' => 'your-app-secret', 42 | 'redirect' => 'http://localhost/socialite/callback.php', 43 | ], 44 | ]; 45 | 46 | $socialite = new SocialiteManager($config); 47 | 48 | $socialite->driver('wechat')->redirect(); 49 | 50 | ``` 51 | 52 | `callback.php`: 53 | 54 | ```php 55 | [ 61 | 'client_id' => 'your-app-id', 62 | 'client_secret' => 'your-app-secret', 63 | 'redirect' => 'http://localhost/socialite/callback.php', 64 | ], 65 | ]; 66 | 67 | $socialite = new SocialiteManager($config); 68 | 69 | $user = $socialite->driver('wechat')->user(); 70 | 71 | $user->getId(); // openid 72 | $user->getNickname(); // "昵称" 73 | $user->getName(); // "昵称" 74 | $user->getAvatar(); // 头像 75 | $user->getProviderName(); // WeChat 76 | ... 77 | ``` 78 | 79 | ### 配置项 80 | 81 | 现在支持: 82 | 83 | `facebook`, `github`, `weibo`, `qq`, `wechat`. 84 | 85 | 每一个登录平台的配置都是一样的,只需要配置: `client_id`, `client_secret`, `redirect`. 86 | 87 | 例子: 88 | ``` 89 | ... 90 | 'weibo' => [ 91 | 'client_id' => 'your-app-id', 92 | 'client_secret' => 'your-app-secret', 93 | 'redirect' => 'http://localhost/socialite/callback.php', 94 | ], 95 | ... 96 | ``` 97 | 98 | ### Scope 99 | 100 | 有些登录平台可以在跳转之前设置Scope: 101 | 102 | ```php 103 | $response = $socialite->driver('github') 104 | ->scopes(['scope1', 'scope2'])->redirect(); 105 | 106 | ``` 107 | > WeChat scopes: 108 | - `snsapi_base`, `snsapi_userinfo` - 用于公众号登录. 109 | - `snsapi_login` - 用户web登录. 110 | 111 | ### 跳转链接 112 | 113 | 当然你也可以动态设置跳转链接: 114 | 115 | ```php 116 | $socialite->redirect($url); 117 | // or 118 | $socialite->withRedirectUrl($url)->redirect(); 119 | // or 120 | $socialite->setRedirectUrl($url)->redirect(); 121 | ``` 122 | 123 | 124 | ### 自定义参数 125 | 126 | 如果存在一些自定义参数,请用with方法 127 | 128 | ```php 129 | $response = $socialite->driver('google') 130 | ->with(['hd' => 'example.com'])->redirect(); 131 | ``` 132 | 133 | ### User interface 134 | 135 | #### Standard user api: 136 | 137 | ```php 138 | 139 | $user = $socialite->driver('weibo')->user(); 140 | ``` 141 | 142 | ```json 143 | { 144 | "id": 1472352, 145 | "nickname": "overtrue", 146 | "name": "安正超", 147 | "email": "anzhengchao@gmail.com", 148 | "avatar": "https://avatars.githubusercontent.com/u/1472352?v=3", 149 | "original": { 150 | "login": "overtrue", 151 | "id": 1472352, 152 | "avatar_url": "https://avatars.githubusercontent.com/u/1472352?v=3", 153 | "gravatar_id": "", 154 | "url": "https://api.github.com/users/overtrue", 155 | "html_url": "https://github.com/overtrue", 156 | ... 157 | }, 158 | "token": { 159 | "access_token": "5b1dc56d64fffbd052359f032716cc4e0a1cb9a0", 160 | "token_type": "bearer", 161 | "scope": "user:email" 162 | } 163 | } 164 | ``` 165 | 166 | 你可以通过数组方式获取用户属性: 167 | 168 | ```php 169 | $user['id']; // 1472352 170 | $user['nickname']; // "overtrue" 171 | $user['name']; // "安正超" 172 | $user['email']; // "anzhengchao@gmail.com" 173 | ... 174 | ``` 175 | 176 | 或者通过对象方式获取: 177 | 178 | ```php 179 | $user->getId(); 180 | $user->getNickname(); 181 | $user->getName(); 182 | $user->getEmail(); 183 | $user->getAvatar(); 184 | $user->getOriginal(); 185 | $user->getToken();// or $user->getAccessToken() 186 | $user->getProviderName(); // GitHub/Google/Facebook... 187 | ``` 188 | 189 | #### 你也可以直接获取各登录平台的原始返回数据 190 | 191 | `$user->getOriginal()` 192 | 193 | #### 获取access token 对象 194 | 195 | `$user->getToken()` 196 | `$user->getAccessToken()` 197 | `$user['token']` 198 | 199 | 200 | ### 可以通过access token 获取用户信息 201 | 202 | ```php 203 | $accessToken = new AccessToken(['access_token' => $accessToken]); 204 | $user = $socialite->user($accessToken); 205 | ``` 206 | 207 | # License 208 | 209 | MIT 210 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "xbing2002/socialite", 3 | "description": "A collection of OAuth 2 packages that extracts from laravel/socialite.", 4 | "keywords": ["OAuth", "social", "login", "Weibo", "WeChat", "QQ"], 5 | "autoload": { 6 | "psr-4": { 7 | "Overtrue\\Socialite\\": "src/", 8 | "App\\":"tests/" 9 | } 10 | }, 11 | "require": { 12 | "php": ">=7.1", 13 | "easyswoole/http": "^1.3", 14 | "easyswoole/http-client": "^1.3", 15 | "easyswoole/cache": "^1.1" 16 | }, 17 | "require-dev": { 18 | "easyswoole/swoole-ide-helper": "^1.0" 19 | }, 20 | "repositories": { 21 | "packagist": { 22 | "type": "composer", 23 | "url": "https://mirrors.aliyun.com/composer/" 24 | } 25 | }, 26 | "license": "MIT", 27 | "authors": [ 28 | { 29 | "name": "overtrue", 30 | "email": "anzhengchao@gmail.com" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/AccessToken.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | use ArrayAccess; 15 | use InvalidArgumentException; 16 | use JsonSerializable; 17 | 18 | /** 19 | * Class AccessToken. 20 | */ 21 | class AccessToken implements AccessTokenInterface, ArrayAccess, JsonSerializable 22 | { 23 | use HasAttributes; 24 | 25 | /** 26 | * AccessToken constructor. 27 | * 28 | * @param array $attributes 29 | */ 30 | public function __construct(array $attributes) 31 | { 32 | var_dump($attributes); 33 | if (empty($attributes['access_token'])) { 34 | throw new InvalidArgumentException('The key "access_token" could not be empty.'); 35 | } 36 | 37 | $this->attributes = $attributes; 38 | } 39 | 40 | /** 41 | * Return the access token string. 42 | * 43 | * @return string 44 | */ 45 | public function getToken() 46 | { 47 | return $this->getAttribute('access_token'); 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function __toString() 54 | { 55 | return strval($this->getAttribute('access_token', '')); 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function jsonSerialize() 62 | { 63 | return $this->getToken(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/AccessTokenInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | /** 15 | * Interface AccessTokenInterface. 16 | */ 17 | interface AccessTokenInterface 18 | { 19 | /** 20 | * Return the access token string. 21 | * 22 | * @return string 23 | */ 24 | public function getToken(); 25 | } 26 | -------------------------------------------------------------------------------- /src/AuthorizeFailedException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | class AuthorizeFailedException extends \RuntimeException 15 | { 16 | /** 17 | * Response body. 18 | * 19 | * @var array 20 | */ 21 | public $body; 22 | 23 | /** 24 | * Constructor. 25 | * 26 | * @param string $message 27 | * @param array $body 28 | */ 29 | public function __construct($message, $body) 30 | { 31 | parent::__construct($message, -1); 32 | 33 | $this->body = $body; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Config.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | use ArrayAccess; 15 | use InvalidArgumentException; 16 | 17 | /** 18 | * Class Config. 19 | */ 20 | class Config implements ArrayAccess 21 | { 22 | /** 23 | * @var array 24 | */ 25 | protected $config; 26 | 27 | /** 28 | * Config constructor. 29 | * 30 | * @param array $config 31 | */ 32 | public function __construct(array $config) 33 | { 34 | $this->config = $config; 35 | } 36 | 37 | /** 38 | * Get an item from an array using "dot" notation. 39 | * 40 | * @param string $key 41 | * @param mixed $default 42 | * 43 | * @return mixed 44 | */ 45 | public function get($key, $default = null) 46 | { 47 | $config = $this->config; 48 | 49 | if (is_null($key)) { 50 | return $config; 51 | } 52 | if (isset($config[$key])) { 53 | return $config[$key]; 54 | } 55 | foreach (explode('.', $key) as $segment) { 56 | if (!is_array($config) || !array_key_exists($segment, $config)) { 57 | return $default; 58 | } 59 | $config = $config[$segment]; 60 | } 61 | 62 | return $config; 63 | } 64 | 65 | /** 66 | * Set an array item to a given value using "dot" notation. 67 | * 68 | * @param string $key 69 | * @param mixed $value 70 | * 71 | * @return array 72 | */ 73 | public function set($key, $value) 74 | { 75 | if (is_null($key)) { 76 | throw new InvalidArgumentException('Invalid config key.'); 77 | } 78 | 79 | $keys = explode('.', $key); 80 | $config = &$this->config; 81 | 82 | while (count($keys) > 1) { 83 | $key = array_shift($keys); 84 | if (!isset($config[$key]) || !is_array($config[$key])) { 85 | $config[$key] = []; 86 | } 87 | $config = &$config[$key]; 88 | } 89 | 90 | $config[array_shift($keys)] = $value; 91 | 92 | return $config; 93 | } 94 | 95 | /** 96 | * Determine if the given configuration value exists. 97 | * 98 | * @param string $key 99 | * 100 | * @return bool 101 | */ 102 | public function has($key) 103 | { 104 | return (bool) $this->get($key); 105 | } 106 | 107 | /** 108 | * Whether a offset exists. 109 | * 110 | * @see http://php.net/manual/en/arrayaccess.offsetexists.php 111 | * 112 | * @param mixed $offset

113 | * An offset to check for. 114 | *

115 | * 116 | * @return bool true on success or false on failure. 117 | *

118 | *

119 | * The return value will be casted to boolean if non-boolean was returned 120 | * 121 | * @since 5.0.0 122 | */ 123 | public function offsetExists($offset) 124 | { 125 | return array_key_exists($offset, $this->config); 126 | } 127 | 128 | /** 129 | * Offset to retrieve. 130 | * 131 | * @see http://php.net/manual/en/arrayaccess.offsetget.php 132 | * 133 | * @param mixed $offset

134 | * The offset to retrieve. 135 | *

136 | * 137 | * @return mixed Can return all value types 138 | * 139 | * @since 5.0.0 140 | */ 141 | public function offsetGet($offset) 142 | { 143 | return $this->get($offset); 144 | } 145 | 146 | /** 147 | * Offset to set. 148 | * 149 | * @see http://php.net/manual/en/arrayaccess.offsetset.php 150 | * 151 | * @param mixed $offset

152 | * The offset to assign the value to. 153 | *

154 | * @param mixed $value

155 | * The value to set. 156 | *

157 | * 158 | * @since 5.0.0 159 | */ 160 | public function offsetSet($offset, $value) 161 | { 162 | $this->set($offset, $value); 163 | } 164 | 165 | /** 166 | * Offset to unset. 167 | * 168 | * @see http://php.net/manual/en/arrayaccess.offsetunset.php 169 | * 170 | * @param mixed $offset

171 | * The offset to unset. 172 | *

173 | * 174 | * @since 5.0.0 175 | */ 176 | public function offsetUnset($offset) 177 | { 178 | $this->set($offset, null); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/FactoryInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | /** 15 | * Interface FactoryInterface. 16 | */ 17 | interface FactoryInterface 18 | { 19 | /** 20 | * Get an OAuth provider implementation. 21 | * 22 | * @param string $driver 23 | * 24 | * @return \Overtrue\Socialite\ProviderInterface 25 | */ 26 | public function driver($driver); 27 | } 28 | -------------------------------------------------------------------------------- /src/HasAttributes.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | /** 15 | * Trait HasAttributes. 16 | */ 17 | trait HasAttributes 18 | { 19 | /** 20 | * @var array 21 | */ 22 | protected $attributes = []; 23 | 24 | /** 25 | * Return the attributes. 26 | * 27 | * @return array 28 | */ 29 | public function getAttributes() 30 | { 31 | return $this->attributes; 32 | } 33 | 34 | /** 35 | * Return the extra attribute. 36 | * 37 | * @param string $name 38 | * @param string $default 39 | * 40 | * @return mixed 41 | */ 42 | public function getAttribute($name, $default = null) 43 | { 44 | return isset($this->attributes[$name]) ? $this->attributes[$name] : $default; 45 | } 46 | 47 | /** 48 | * Set extra attributes. 49 | * 50 | * @param string $name 51 | * @param mixed $value 52 | * 53 | * @return $this 54 | */ 55 | public function setAttribute($name, $value) 56 | { 57 | $this->attributes[$name] = $value; 58 | 59 | return $this; 60 | } 61 | 62 | /** 63 | * Map the given array onto the user's properties. 64 | * 65 | * @param array $attributes 66 | * 67 | * @return $this 68 | */ 69 | public function merge(array $attributes) 70 | { 71 | $this->attributes = array_merge($this->attributes, $attributes); 72 | 73 | return $this; 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | */ 79 | public function offsetExists($offset) 80 | { 81 | return array_key_exists($offset, $this->attributes); 82 | } 83 | 84 | /** 85 | * {@inheritdoc} 86 | */ 87 | public function offsetGet($offset) 88 | { 89 | return $this->getAttribute($offset); 90 | } 91 | 92 | /** 93 | * {@inheritdoc} 94 | */ 95 | public function offsetSet($offset, $value) 96 | { 97 | $this->setAttribute($offset, $value); 98 | } 99 | 100 | /** 101 | * {@inheritdoc} 102 | */ 103 | public function offsetUnset($offset) 104 | { 105 | unset($this->attributes[$offset]); 106 | } 107 | 108 | /** 109 | * {@inheritdoc} 110 | */ 111 | public function __get($property) 112 | { 113 | return $this->getAttribute($property); 114 | } 115 | 116 | /** 117 | * Return array. 118 | * 119 | * @return array 120 | */ 121 | public function toArray() 122 | { 123 | return $this->getAttributes(); 124 | } 125 | 126 | /** 127 | * Return JSON. 128 | * 129 | * @return string 130 | */ 131 | public function toJSON() 132 | { 133 | return json_encode($this->getAttributes(), JSON_UNESCAPED_UNICODE); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/InvalidArgumentException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | class InvalidArgumentException extends \InvalidArgumentException 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /src/InvalidStateException.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | class InvalidStateException extends \InvalidArgumentException 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /src/ProviderInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | interface ProviderInterface 15 | { 16 | 17 | /** 18 | * Redirect the user to the authentication page for the provider. 19 | * 20 | * @return boolean 21 | */ 22 | public function redirect(); 23 | 24 | /** 25 | * Get the User instance for the authenticated user. 26 | * 27 | * @param \Overtrue\Socialite\AccessTokenInterface $token 28 | * 29 | * @return \Overtrue\Socialite\User 30 | */ 31 | public function user(AccessTokenInterface $token = null); 32 | } 33 | -------------------------------------------------------------------------------- /src/Providers/AbstractProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite\Providers; 13 | 14 | use easySwoole\Cache\Cache; 15 | use EasySwoole\Http\Response; 16 | use EasySwoole\HttpClient\HttpClient; 17 | use Overtrue\Socialite\AccessToken; 18 | use Overtrue\Socialite\AccessTokenInterface; 19 | use Overtrue\Socialite\AuthorizeFailedException; 20 | use Overtrue\Socialite\InvalidStateException; 21 | use Overtrue\Socialite\ProviderInterface; 22 | use EasySwoole\Http\Request; 23 | 24 | /** 25 | * Class SessionDriverInterface. 26 | */ 27 | abstract class AbstractProvider implements ProviderInterface 28 | { 29 | /** 30 | * AbstractProvider name. 31 | * 32 | * @var string 33 | */ 34 | protected $name; 35 | 36 | /** 37 | * The HTTP request instance. 38 | * 39 | * @var Request 40 | */ 41 | protected $request; 42 | 43 | /** 44 | * The HTTP response instance. 45 | * 46 | * @var Request 47 | */ 48 | protected $response; 49 | 50 | /** 51 | * The client ID. 52 | * 53 | * @var string 54 | */ 55 | protected $clientId; 56 | 57 | /** 58 | * The client secret. 59 | * 60 | * @var string 61 | */ 62 | protected $clientSecret; 63 | 64 | /** 65 | * @var \Overtrue\Socialite\AccessTokenInterface 66 | */ 67 | protected $accessToken; 68 | 69 | /** 70 | * The redirect URL. 71 | * 72 | * @var string 73 | */ 74 | protected $redirectUrl; 75 | 76 | /** 77 | * The custom parameters to be sent with the request. 78 | * 79 | * @var array 80 | */ 81 | protected $parameters = []; 82 | 83 | /** 84 | * The scopes being requested. 85 | * 86 | * @var array 87 | */ 88 | protected $scopes = []; 89 | 90 | /** 91 | * The separating character for the requested scopes. 92 | * 93 | * @var string 94 | */ 95 | protected $scopeSeparator = ','; 96 | 97 | /** 98 | * The type of the encoding in the query. 99 | * 100 | * @var int Can be either PHP_QUERY_RFC3986 or PHP_QUERY_RFC1738 101 | */ 102 | protected $encodingType = PHP_QUERY_RFC1738; 103 | 104 | /** 105 | * Indicates if the session state should be utilized. 106 | * 107 | * @var bool 108 | */ 109 | protected $stateless = false; 110 | 111 | /** 112 | * The options for guzzle\client. 113 | * 114 | * @var array 115 | */ 116 | protected static $guzzleOptions = ['http_errors' => false]; 117 | 118 | /** @var SessionDriver */ 119 | protected $session; 120 | 121 | /** 122 | * Create a new provider instance. 123 | * 124 | * @param Request $request 125 | * @param Response $response 126 | * @param string $clientId 127 | * @param string $clientSecret 128 | * @param string|null $redirectUrl 129 | */ 130 | public function __construct(Request $request, Response $response, $clientId, $clientSecret, $redirectUrl = null) 131 | { 132 | $this->request = $request; 133 | $this->response=$response; 134 | $this->clientId = $clientId; 135 | $this->clientSecret = $clientSecret; 136 | $this->redirectUrl = $redirectUrl; 137 | 138 | $sessionManager= new SessionManager('file',$this->request,$this->response); 139 | $this->session=$sessionManager->session(); 140 | $this->session->start(); 141 | } 142 | 143 | /** 144 | * Get the authentication URL for the provider. 145 | * 146 | * @param string $state 147 | * 148 | * @return string 149 | */ 150 | abstract protected function getAuthUrl($state); 151 | 152 | /** 153 | * Get the token URL for the provider. 154 | * 155 | * @return string 156 | */ 157 | abstract protected function getTokenUrl(); 158 | 159 | /** 160 | * Get the raw user for the given access token. 161 | * 162 | * @param \Overtrue\Socialite\AccessTokenInterface $token 163 | * 164 | * @return array 165 | */ 166 | abstract protected function getUserByToken(AccessTokenInterface $token); 167 | 168 | /** 169 | * Map the raw user array to a Socialite User instance. 170 | * 171 | * @param array $user 172 | * 173 | * @return \Overtrue\Socialite\User 174 | */ 175 | abstract protected function mapUserToObject(array $user); 176 | 177 | 178 | /** 179 | * Redirect the user of the application to the provider's authentication screen. 180 | * 181 | * @param string $redirectUrl 182 | * 183 | * @return string 184 | */ 185 | public function redirect($redirectUrl = null) 186 | { 187 | $state = null; 188 | 189 | if (!is_null($redirectUrl)) { 190 | $this->redirectUrl = $redirectUrl; 191 | } 192 | if ($this->usesState()) { 193 | $state = $this->makeState(); 194 | } 195 | 196 | return $this->response->redirect($this->getAuthUrl($state)); 197 | //return new RedirectResponse($this->getAuthUrl($state)); 198 | } 199 | 200 | /** 201 | * {@inheritdoc} 202 | */ 203 | public function user(AccessTokenInterface $token = null) 204 | { 205 | if (is_null($token) && $this->hasInvalidState()) { 206 | throw new InvalidStateException(); 207 | } 208 | $token = $token ?: $this->getAccessToken($this->getCode()); 209 | $user = $this->getUserByToken($token); 210 | 211 | $user = $this->mapUserToObject($user)->merge(['original' => $user]); 212 | 213 | return $user->setToken($token)->setProviderName($this->getName()); 214 | } 215 | 216 | /** 217 | * Set redirect url. 218 | * 219 | * @param string $redirectUrl 220 | * 221 | * @return $this 222 | */ 223 | public function setRedirectUrl($redirectUrl) 224 | { 225 | $this->redirectUrl = $redirectUrl; 226 | 227 | return $this; 228 | } 229 | 230 | /** 231 | * Set redirect url. 232 | * 233 | * @param string $redirectUrl 234 | * 235 | * @return $this 236 | */ 237 | public function withRedirectUrl($redirectUrl) 238 | { 239 | $this->redirectUrl = $redirectUrl; 240 | 241 | return $this; 242 | } 243 | 244 | /** 245 | * Return the redirect url. 246 | * 247 | * @return string 248 | */ 249 | public function getRedirectUrl() 250 | { 251 | return $this->redirectUrl; 252 | } 253 | 254 | /** 255 | * @param \Overtrue\Socialite\AccessTokenInterface $accessToken 256 | * 257 | * @return $this 258 | */ 259 | public function setAccessToken(AccessTokenInterface $accessToken) 260 | { 261 | $this->accessToken = $accessToken; 262 | 263 | return $this; 264 | } 265 | 266 | /** 267 | * Get the access token for the given code. 268 | * 269 | * @param string $code 270 | * 271 | * @return \Overtrue\Socialite\AccessTokenInterface 272 | */ 273 | public function getAccessToken($code) 274 | { 275 | if ($this->accessToken) { 276 | return $this->accessToken; 277 | } 278 | 279 | 280 | 281 | $response = $this->getHttpClient() 282 | ->setUrl($this->getTokenUrl()) 283 | ->post($this->getTokenFields($code),['Accept' => 'application/json']); 284 | 285 | return $this->parseAccessToken($response->getBody()); 286 | } 287 | 288 | /** 289 | * Set the scopes of the requested access. 290 | * 291 | * @param array $scopes 292 | * 293 | * @return $this 294 | */ 295 | public function scopes(array $scopes) 296 | { 297 | $this->scopes = $scopes; 298 | 299 | return $this; 300 | } 301 | 302 | /** 303 | * Set the request instance. 304 | * 305 | * @param Request $request 306 | * 307 | * @return $this 308 | */ 309 | public function setRequest(Request $request) 310 | { 311 | $this->request = $request; 312 | 313 | return $this; 314 | } 315 | 316 | /** 317 | * Get the request instance. 318 | * 319 | * @return Request 320 | */ 321 | public function getRequest() 322 | { 323 | return $this->request; 324 | } 325 | 326 | /** 327 | * Indicates that the provider should operate as stateless. 328 | * 329 | * @return $this 330 | */ 331 | public function stateless() 332 | { 333 | $this->stateless = true; 334 | 335 | return $this; 336 | } 337 | 338 | /** 339 | * Set the custom parameters of the request. 340 | * 341 | * @param array $parameters 342 | * 343 | * @return $this 344 | */ 345 | public function with(array $parameters) 346 | { 347 | $this->parameters = $parameters; 348 | 349 | return $this; 350 | } 351 | 352 | /** 353 | * @throws \ReflectionException 354 | * 355 | * @return string 356 | */ 357 | public function getName() 358 | { 359 | if (empty($this->name)) { 360 | $this->name = strstr((new \ReflectionClass(get_class($this)))->getShortName(), 'AbstractProvider', true); 361 | } 362 | 363 | return $this->name; 364 | } 365 | 366 | /** 367 | * Get the authentication URL for the provider. 368 | * 369 | * @param string $url 370 | * @param string $state 371 | * 372 | * @return string 373 | */ 374 | protected function buildAuthUrlFromBase($url, $state) 375 | { 376 | return $url.'?'.http_build_query($this->getCodeFields($state), '', '&', $this->encodingType); 377 | } 378 | 379 | /** 380 | * Get the GET parameters for the code request. 381 | * 382 | * @param string|null $state 383 | * 384 | * @return array 385 | */ 386 | protected function getCodeFields($state = null) 387 | { 388 | $fields = array_merge([ 389 | 'client_id' => $this->clientId, 390 | 'redirect_uri' => $this->redirectUrl, 391 | 'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator), 392 | 'response_type' => 'code', 393 | ], $this->parameters); 394 | 395 | if ($this->usesState()) { 396 | $fields['state'] = $state; 397 | } 398 | 399 | return $fields; 400 | } 401 | 402 | /** 403 | * Format the given scopes. 404 | * 405 | * @param array $scopes 406 | * @param string $scopeSeparator 407 | * 408 | * @return string 409 | */ 410 | protected function formatScopes(array $scopes, $scopeSeparator) 411 | { 412 | return implode($scopeSeparator, $scopes); 413 | } 414 | 415 | /** 416 | * Determine if the current request / session has a mismatching "state". 417 | * 418 | * @return bool 419 | */ 420 | protected function hasInvalidState() 421 | { 422 | if ($this->isStateless()) { 423 | return false; 424 | } 425 | $cookie=$this->request->getCookieParams('EsLoginSession'); 426 | if(empty($cookie)) 427 | { 428 | return false; 429 | } 430 | Cache::init(); 431 | $state=Cache::get($cookie); 432 | return !(strlen($state) > 0); 433 | } 434 | 435 | /** 436 | * Get the POST fields for the token request. 437 | * 438 | * @param string $code 439 | * 440 | * @return array 441 | */ 442 | protected function getTokenFields($code) 443 | { 444 | return [ 445 | 'client_id' => $this->clientId, 446 | 'client_secret' => $this->clientSecret, 447 | 'code' => $code, 448 | 'redirect_uri' => $this->redirectUrl, 449 | ]; 450 | } 451 | 452 | /** 453 | * Get the access token from the token response body. 454 | * 455 | * @param \Psr\Http\Message\StreamInterface|array $body 456 | * 457 | * @return \Overtrue\Socialite\AccessTokenInterface 458 | */ 459 | protected function parseAccessToken($body) 460 | { 461 | if (!is_array($body)) { 462 | $body = json_decode($body, true); 463 | } 464 | if (empty($body['access_token'])) { 465 | throw new AuthorizeFailedException('Authorize Failed: '.json_encode($body, JSON_UNESCAPED_UNICODE), $body); 466 | } 467 | 468 | return new AccessToken($body); 469 | } 470 | 471 | /** 472 | * Get the code from the request. 473 | * 474 | * @return string 475 | */ 476 | protected function getCode() 477 | { 478 | return $this->request->getQueryParam('code'); 479 | } 480 | 481 | /** 482 | * Get a fresh instance of the Guzzle HTTP client. 483 | * 484 | * @return HttpClient 485 | */ 486 | protected function getHttpClient() 487 | { 488 | //这儿后期加上httpclient的config 489 | return new HttpClient(); 490 | //return new Client(self::$guzzleOptions); 491 | } 492 | 493 | 494 | 495 | /** 496 | * Determine if the provider is operating with state. 497 | * 498 | * @return bool 499 | */ 500 | protected function usesState() 501 | { 502 | return !$this->stateless; 503 | } 504 | 505 | /** 506 | * Determine if the provider is operating as stateless. 507 | * 508 | * @return bool 509 | */ 510 | protected function isStateless() 511 | { 512 | return $this->stateless; 513 | } 514 | 515 | /** 516 | * Return array item by key. 517 | * 518 | * @param array $array 519 | * @param string $key 520 | * @param mixed $default 521 | * 522 | * @return mixed 523 | */ 524 | protected function arrayItem(array $array, $key, $default = null) 525 | { 526 | if (is_null($key)) { 527 | return $array; 528 | } 529 | 530 | if (isset($array[$key])) { 531 | return $array[$key]; 532 | } 533 | 534 | foreach (explode('.', $key) as $segment) { 535 | if (!is_array($array) || !array_key_exists($segment, $array)) { 536 | return $default; 537 | } 538 | 539 | $array = $array[$segment]; 540 | } 541 | 542 | return $array; 543 | } 544 | 545 | /** 546 | * Put state to session storage and return it. 547 | * 548 | * @return string|bool 549 | */ 550 | protected function makeState() 551 | { 552 | $state = sha1(uniqid(mt_rand(1, 1000000), true)); 553 | $this->response->setCookie('EsLoginSession',$state,1440); 554 | Cache::init(); 555 | Cache::set($state,$state); 556 | 557 | return $state; 558 | } 559 | } 560 | -------------------------------------------------------------------------------- /src/Providers/FacebookProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite\Providers; 13 | 14 | use Overtrue\Socialite\AccessTokenInterface; 15 | use Overtrue\Socialite\ProviderInterface; 16 | use Overtrue\Socialite\User; 17 | 18 | /** 19 | * Class FacebookProvider. 20 | * 21 | * @see https://developers.facebook.com/docs/graph-api [Facebook - Graph API] 22 | */ 23 | class FacebookProvider extends AbstractProvider implements ProviderInterface 24 | { 25 | /** 26 | * The base Facebook Graph URL. 27 | * 28 | * @var string 29 | */ 30 | protected $graphUrl = 'https://graph.facebook.com'; 31 | 32 | /** 33 | * The Graph API version for the request. 34 | * 35 | * @var string 36 | */ 37 | protected $version = 'v3.3'; 38 | 39 | /** 40 | * The user fields being requested. 41 | * 42 | * @var array 43 | */ 44 | protected $fields = ['first_name', 'last_name', 'email', 'gender', 'verified']; 45 | 46 | /** 47 | * The scopes being requested. 48 | * 49 | * @var array 50 | */ 51 | protected $scopes = ['email']; 52 | 53 | /** 54 | * Display the dialog in a popup view. 55 | * 56 | * @var bool 57 | */ 58 | protected $popup = false; 59 | 60 | /** 61 | * {@inheritdoc} 62 | */ 63 | protected function getAuthUrl($state) 64 | { 65 | return $this->buildAuthUrlFromBase('https://www.facebook.com/'.$this->version.'/dialog/oauth', $state); 66 | } 67 | 68 | /** 69 | * {@inheritdoc} 70 | */ 71 | protected function getTokenUrl() 72 | { 73 | return $this->graphUrl.'/oauth/access_token'; 74 | } 75 | 76 | /** 77 | * Get the access token for the given code. 78 | * 79 | * @param string $code 80 | * 81 | * @return \Overtrue\Socialite\AccessToken 82 | */ 83 | public function getAccessToken($code) 84 | { 85 | $response = $this->getHttpClient() 86 | ->setUrl($this->getTokenUrl()) 87 | ->setQuery($this->getTokenFields($code)) 88 | ->get(); 89 | 90 | return $this->parseAccessToken($response->getBody()); 91 | } 92 | 93 | /** 94 | * {@inheritdoc} 95 | */ 96 | protected function getUserByToken(AccessTokenInterface $token) 97 | { 98 | $appSecretProof = hash_hmac('sha256', $token->getToken(), $this->clientSecret); 99 | 100 | $response = $this->getHttpClient() 101 | ->setUrl($this->graphUrl.'/'.$this->version.'/me?access_token='.$token.'&appsecret_proof='.$appSecretProof.'&fields='.implode(',', $this->fields)) 102 | ->get( ['Accept' => 'application/json']); 103 | 104 | return json_decode($response->getBody(), true); 105 | } 106 | 107 | /** 108 | * {@inheritdoc} 109 | */ 110 | protected function mapUserToObject(array $user) 111 | { 112 | $avatarUrl = $this->graphUrl.'/'.$this->version.'/'.$user['id'].'/picture'; 113 | 114 | $firstName = $this->arrayItem($user, 'first_name'); 115 | $lastName = $this->arrayItem($user, 'last_name'); 116 | 117 | return new User([ 118 | 'id' => $this->arrayItem($user, 'id'), 119 | 'nickname' => null, 120 | 'name' => $firstName.' '.$lastName, 121 | 'email' => $this->arrayItem($user, 'email'), 122 | 'avatar' => $avatarUrl.'?type=normal', 123 | 'avatar_original' => $avatarUrl.'?width=1920', 124 | ]); 125 | } 126 | 127 | /** 128 | * {@inheritdoc} 129 | */ 130 | protected function getCodeFields($state = null) 131 | { 132 | $fields = parent::getCodeFields($state); 133 | 134 | if ($this->popup) { 135 | $fields['display'] = 'popup'; 136 | } 137 | 138 | return $fields; 139 | } 140 | 141 | /** 142 | * Set the user fields to request from Facebook. 143 | * 144 | * @param array $fields 145 | * 146 | * @return $this 147 | */ 148 | public function fields(array $fields) 149 | { 150 | $this->fields = $fields; 151 | 152 | return $this; 153 | } 154 | 155 | /** 156 | * Set the dialog to be displayed as a popup. 157 | * 158 | * @return $this 159 | */ 160 | public function asPopup() 161 | { 162 | $this->popup = true; 163 | 164 | return $this; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/Providers/GitHubProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite\Providers; 13 | 14 | use Exception; 15 | use Overtrue\Socialite\AccessTokenInterface; 16 | use Overtrue\Socialite\ProviderInterface; 17 | use Overtrue\Socialite\User; 18 | 19 | /** 20 | * Class GitHubProvider. 21 | */ 22 | class GitHubProvider extends AbstractProvider implements ProviderInterface 23 | { 24 | /** 25 | * The scopes being requested. 26 | * 27 | * @var array 28 | */ 29 | protected $scopes = ['user:email']; 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | protected function getAuthUrl($state) 35 | { 36 | return $this->buildAuthUrlFromBase('https://github.com/login/oauth/authorize', $state); 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | protected function getTokenUrl() 43 | { 44 | return 'https://github.com/login/oauth/access_token'; 45 | } 46 | 47 | public function getAccessToken($code) 48 | { 49 | $response =$this->getHttpClient() 50 | ->setUrl($this->getTokenUrl()) 51 | ->setQuery($this->getTokenFields($code)) 52 | ->get(['Accept' => 'application/json']); 53 | 54 | return $this->parseAccessToken($response->getBody()); 55 | } 56 | 57 | protected function getTokenFields($code) 58 | { 59 | return array_filter([ 60 | 'client_id' => $this->clientId, 61 | 'client_secret' => $this->clientSecret, 62 | 'code' => $code, 63 | ]); 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | protected function getUserByToken(AccessTokenInterface $token) 70 | { 71 | $userUrl = 'https://api.github.com/user?access_token='.$token->getToken(); 72 | $response = $this->getHttpClient()->setUrl($userUrl)->get($this->getRequestOptions()); 73 | 74 | 75 | $user = json_decode($response->getBody(), true); 76 | 77 | if (in_array('user:email', $this->scopes)) { 78 | $user['email'] = $this->getEmailByToken($token); 79 | } 80 | 81 | return $user; 82 | } 83 | 84 | /** 85 | * Get the email for the given access token. 86 | * 87 | * @param string $token 88 | * 89 | * @return string|null 90 | */ 91 | protected function getEmailByToken($token) 92 | { 93 | $emailsUrl = 'https://api.github.com/user/emails?access_token='.$token->getToken(); 94 | 95 | try { 96 | $response = $this->getHttpClient()->setUrl($emailsUrl)->get($this->getRequestOptions()); 97 | 98 | } catch (Exception $e) { 99 | return; 100 | } 101 | 102 | foreach (json_decode($response->getBody(), true) as $email) { 103 | if ($email['primary'] && $email['verified']) { 104 | return $email['email']; 105 | } 106 | } 107 | } 108 | 109 | /** 110 | * {@inheritdoc} 111 | */ 112 | protected function mapUserToObject(array $user) 113 | { 114 | return new User([ 115 | 'id' => $this->arrayItem($user, 'id'), 116 | 'username' => $this->arrayItem($user, 'login'), 117 | 'nickname' => $this->arrayItem($user, 'login'), 118 | 'name' => $this->arrayItem($user, 'name'), 119 | 'email' => $this->arrayItem($user, 'email'), 120 | 'avatar' => $this->arrayItem($user, 'avatar_url'), 121 | ]); 122 | } 123 | 124 | /** 125 | * Get the default options for an HTTP request. 126 | * 127 | * @return array 128 | */ 129 | protected function getRequestOptions() 130 | { 131 | return [ 132 | 'Accept' => 'application/vnd.github.v3+json', 133 | ]; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/Providers/QQProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite\Providers; 13 | 14 | use Overtrue\Socialite\AccessTokenInterface; 15 | use Overtrue\Socialite\ProviderInterface; 16 | use Overtrue\Socialite\User; 17 | 18 | /** 19 | * Class QQProvider. 20 | * 21 | * @see http://wiki.connect.qq.com/oauth2-0%E7%AE%80%E4%BB%8B [QQ - OAuth 2.0 登录QQ] 22 | */ 23 | class QQProvider extends AbstractProvider implements ProviderInterface 24 | { 25 | /** 26 | * The base url of QQ API. 27 | * 28 | * @var string 29 | */ 30 | protected $baseUrl = 'https://graph.qq.com'; 31 | 32 | /** 33 | * User openid. 34 | * 35 | * @var string 36 | */ 37 | protected $openId; 38 | 39 | /** 40 | * get token(openid) with unionid. 41 | * 42 | * @var bool 43 | */ 44 | protected $withUnionId = false; 45 | 46 | /** 47 | * User unionid. 48 | * 49 | * @var string 50 | */ 51 | protected $unionId; 52 | 53 | /** 54 | * The scopes being requested. 55 | * 56 | * @var array 57 | */ 58 | protected $scopes = ['get_user_info']; 59 | 60 | /** 61 | * The uid of user authorized. 62 | * 63 | * @var int 64 | */ 65 | protected $uid; 66 | 67 | /** 68 | * Get the authentication URL for the provider. 69 | * 70 | * @param string $state 71 | * 72 | * @return string 73 | */ 74 | protected function getAuthUrl($state) 75 | { 76 | return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth2.0/authorize', $state); 77 | } 78 | 79 | /** 80 | * Get the token URL for the provider. 81 | * 82 | * @return string 83 | */ 84 | protected function getTokenUrl() 85 | { 86 | return $this->baseUrl.'/oauth2.0/token'; 87 | } 88 | 89 | /** 90 | * Get the Post fields for the token request. 91 | * 92 | * @param string $code 93 | * 94 | * @return array 95 | */ 96 | protected function getTokenFields($code) 97 | { 98 | return parent::getTokenFields($code) + ['grant_type' => 'authorization_code']; 99 | } 100 | 101 | /** 102 | * Get the access token for the given code. 103 | * 104 | * @param string $code 105 | * 106 | * @return \Overtrue\Socialite\AccessToken 107 | */ 108 | public function getAccessToken($code) 109 | { 110 | $response = $this->getHttpClient()->setUrl($this->getTokenUrl()) 111 | ->setQuery($this->getTokenFields($code)) 112 | ->get(); 113 | 114 | return $this->parseAccessToken($response->getBody()->getContents()); 115 | } 116 | 117 | /** 118 | * Get the access token from the token response body. 119 | * 120 | * @param string $body 121 | * 122 | * @return \Overtrue\Socialite\AccessToken 123 | */ 124 | public function parseAccessToken($body) 125 | { 126 | parse_str($body, $token); 127 | 128 | return parent::parseAccessToken($token); 129 | } 130 | 131 | /** 132 | * @return self 133 | */ 134 | public function withUnionId() 135 | { 136 | $this->withUnionId = true; 137 | 138 | return $this; 139 | } 140 | 141 | /** 142 | * Get the raw user for the given access token. 143 | * 144 | * @param \Overtrue\Socialite\AccessTokenInterface $token 145 | * 146 | * @return array 147 | */ 148 | protected function getUserByToken(AccessTokenInterface $token) 149 | { 150 | $url = $this->baseUrl.'/oauth2.0/me?access_token='.$token->getToken(); 151 | $this->withUnionId && $url .= '&unionid=1'; 152 | 153 | $response = $this->getHttpClient()->get($url); 154 | 155 | $me = json_decode($this->removeCallback($response->getBody()->getContents()), true); 156 | $this->openId = $me['openid']; 157 | $this->unionId = isset($me['unionid']) ? $me['unionid'] : ''; 158 | 159 | $queries = [ 160 | 'access_token' => $token->getToken(), 161 | 'openid' => $this->openId, 162 | 'oauth_consumer_key' => $this->clientId, 163 | ]; 164 | 165 | $response = $this->getHttpClient() 166 | ->setUrl($this->baseUrl.'/user/get_user_info?'.http_build_query($queries)) 167 | ->get(); 168 | 169 | return json_decode($this->removeCallback($response->getBody()->getContents()), true); 170 | } 171 | 172 | /** 173 | * Map the raw user array to a Socialite User instance. 174 | * 175 | * @param array $user 176 | * 177 | * @return \Overtrue\Socialite\User 178 | */ 179 | protected function mapUserToObject(array $user) 180 | { 181 | return new User([ 182 | 'id' => $this->openId, 183 | 'unionid' => $this->unionId, 184 | 'nickname' => $this->arrayItem($user, 'nickname'), 185 | 'name' => $this->arrayItem($user, 'nickname'), 186 | 'email' => $this->arrayItem($user, 'email'), 187 | 'avatar' => $this->arrayItem($user, 'figureurl_qq_2'), 188 | ]); 189 | } 190 | 191 | /** 192 | * Remove the fucking callback parentheses. 193 | * 194 | * @param string $response 195 | * 196 | * @return string 197 | */ 198 | protected function removeCallback($response) 199 | { 200 | if (false !== strpos($response, 'callback')) { 201 | $lpos = strpos($response, '('); 202 | $rpos = strrpos($response, ')'); 203 | $response = substr($response, $lpos + 1, $rpos - $lpos - 1); 204 | } 205 | 206 | return $response; 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/Providers/WeChatProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite\Providers; 13 | 14 | use Overtrue\Socialite\AccessTokenInterface; 15 | use Overtrue\Socialite\InvalidArgumentException; 16 | use Overtrue\Socialite\ProviderInterface; 17 | use Overtrue\Socialite\User; 18 | use Overtrue\Socialite\WeChatComponentInterface; 19 | 20 | /** 21 | * Class WeChatProvider. 22 | * 23 | * @see http://mp.weixin.qq.com/wiki/9/01f711493b5a02f24b04365ac5d8fd95.html [WeChat - 公众平台OAuth文档] 24 | * @see https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN [网站应用微信登录开发指南] 25 | */ 26 | class WeChatProvider extends AbstractProvider implements ProviderInterface 27 | { 28 | /** 29 | * The base url of WeChat API. 30 | * 31 | * @var string 32 | */ 33 | protected $baseUrl = 'https://api.weixin.qq.com/sns'; 34 | 35 | /** 36 | * {@inheritdoc}. 37 | */ 38 | protected $openId; 39 | 40 | /** 41 | * {@inheritdoc}. 42 | */ 43 | protected $scopes = ['snsapi_login']; 44 | 45 | /** 46 | * Indicates if the session state should be utilized. 47 | * 48 | * @var bool 49 | */ 50 | protected $stateless = true; 51 | 52 | /** 53 | * Return country code instead of country name. 54 | * 55 | * @var bool 56 | */ 57 | protected $withCountryCode = false; 58 | 59 | /** 60 | * @var WeChatComponentInterface 61 | */ 62 | protected $component; 63 | 64 | /** 65 | * Return country code instead of country name. 66 | * 67 | * @return $this 68 | */ 69 | public function withCountryCode() 70 | { 71 | $this->withCountryCode = true; 72 | 73 | return $this; 74 | } 75 | 76 | /** 77 | * WeChat OpenPlatform 3rd component. 78 | * 79 | * @param WeChatComponentInterface $component 80 | * 81 | * @return $this 82 | */ 83 | public function component(WeChatComponentInterface $component) 84 | { 85 | $this->scopes = ['snsapi_base']; 86 | 87 | $this->component = $component; 88 | 89 | return $this; 90 | } 91 | 92 | /** 93 | * {@inheritdoc}. 94 | */ 95 | public function getAccessToken($code) 96 | { 97 | 98 | $response =$this->getHttpClient() 99 | ->setUrl($this->getTokenUrl()) 100 | ->setQuery($this->getTokenFields($code)) 101 | ->get(['Accept' => 'application/json']); 102 | 103 | return $this->parseAccessToken($response->getBody()); 104 | } 105 | 106 | /** 107 | * {@inheritdoc}. 108 | */ 109 | protected function getAuthUrl($state) 110 | { 111 | $path = 'oauth2/authorize'; 112 | 113 | if (in_array('snsapi_login', $this->scopes)) { 114 | $path = 'qrconnect'; 115 | } 116 | 117 | return $this->buildAuthUrlFromBase("https://open.weixin.qq.com/connect/{$path}", $state); 118 | } 119 | 120 | /** 121 | * {@inheritdoc}. 122 | */ 123 | protected function buildAuthUrlFromBase($url, $state) 124 | { 125 | $query = http_build_query($this->getCodeFields($state), '', '&', $this->encodingType); 126 | 127 | return $url.'?'.$query.'#wechat_redirect'; 128 | } 129 | 130 | /** 131 | * {@inheritdoc}. 132 | */ 133 | protected function getCodeFields($state = null) 134 | { 135 | if ($this->component) { 136 | $this->with(['component_appid' => $this->component->getAppId()]); 137 | } 138 | 139 | return array_merge([ 140 | 'appid' => $this->clientId, 141 | 'redirect_uri' => $this->redirectUrl, 142 | 'response_type' => 'code', 143 | 'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator), 144 | 'state' => $state ?: md5(time()), 145 | 'connect_redirect' => 1, 146 | ], $this->parameters); 147 | } 148 | 149 | /** 150 | * {@inheritdoc}. 151 | */ 152 | protected function getTokenUrl() 153 | { 154 | if ($this->component) { 155 | return $this->baseUrl.'/oauth2/component/access_token'; 156 | } 157 | 158 | return $this->baseUrl.'/oauth2/access_token'; 159 | } 160 | 161 | /** 162 | * {@inheritdoc}. 163 | */ 164 | protected function getUserByToken(AccessTokenInterface $token) 165 | { 166 | $scopes = explode(',', $token->getAttribute('scope', '')); 167 | 168 | if (in_array('snsapi_base', $scopes)) { 169 | return $token->toArray(); 170 | } 171 | 172 | if (empty($token['openid'])) { 173 | throw new InvalidArgumentException('openid of AccessToken is required.'); 174 | } 175 | 176 | $language = $this->withCountryCode ? null : (isset($this->parameters['lang']) ? $this->parameters['lang'] : 'zh_CN'); 177 | 178 | 179 | $response =$this->getHttpClient()->setUrl($this->baseUrl.'/userinfo')->setQuery( 180 | array_filter([ 181 | 'access_token' => $token->getToken(), 182 | 'openid' => $token['openid'], 183 | 'lang' => $language, 184 | ]))->get(); 185 | 186 | return json_decode($response->getBody(), true); 187 | } 188 | 189 | /** 190 | * {@inheritdoc}. 191 | */ 192 | protected function mapUserToObject(array $user) 193 | { 194 | return new User([ 195 | 'id' => $this->arrayItem($user, 'openid'), 196 | 'name' => $this->arrayItem($user, 'nickname'), 197 | 'nickname' => $this->arrayItem($user, 'nickname'), 198 | 'avatar' => $this->arrayItem($user, 'headimgurl'), 199 | 'email' => null, 200 | ]); 201 | } 202 | 203 | /** 204 | * {@inheritdoc}. 205 | */ 206 | protected function getTokenFields($code) 207 | { 208 | return array_filter([ 209 | 'appid' => $this->clientId, 210 | 'secret' => $this->clientSecret, 211 | 'component_appid' => $this->component ? $this->component->getAppId() : null, 212 | 'component_access_token' => $this->component ? $this->component->getToken() : null, 213 | 'code' => $code, 214 | 'grant_type' => 'authorization_code', 215 | ]); 216 | } 217 | 218 | /** 219 | * Remove the fucking callback parentheses. 220 | * 221 | * @param mixed $response 222 | * 223 | * @return string 224 | */ 225 | protected function removeCallback($response) 226 | { 227 | if (false !== strpos($response, 'callback')) { 228 | $lpos = strpos($response, '('); 229 | $rpos = strrpos($response, ')'); 230 | $response = substr($response, $lpos + 1, $rpos - $lpos - 1); 231 | } 232 | 233 | return $response; 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/Providers/WeiboProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite\Providers; 13 | 14 | use Overtrue\Socialite\AccessTokenInterface; 15 | use Overtrue\Socialite\ProviderInterface; 16 | use Overtrue\Socialite\User; 17 | 18 | /** 19 | * Class WeiboProvider. 20 | * 21 | * @see http://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E [OAuth 2.0 授权机制说明] 22 | */ 23 | class WeiboProvider extends AbstractProvider implements ProviderInterface 24 | { 25 | /** 26 | * The base url of Weibo API. 27 | * 28 | * @var string 29 | */ 30 | protected $baseUrl = 'https://api.weibo.com'; 31 | 32 | /** 33 | * The API version for the request. 34 | * 35 | * @var string 36 | */ 37 | protected $version = '2'; 38 | 39 | /** 40 | * The scopes being requested. 41 | * 42 | * @var array 43 | */ 44 | protected $scopes = ['email']; 45 | 46 | /** 47 | * The uid of user authorized. 48 | * 49 | * @var int 50 | */ 51 | protected $uid; 52 | 53 | /** 54 | * Get the authentication URL for the provider. 55 | * 56 | * @param string $state 57 | * 58 | * @return string 59 | */ 60 | protected function getAuthUrl($state) 61 | { 62 | return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth2/authorize', $state); 63 | } 64 | 65 | /** 66 | * Get the token URL for the provider. 67 | * 68 | * @return string 69 | */ 70 | protected function getTokenUrl() 71 | { 72 | return $this->baseUrl.'/'.$this->version.'/oauth2/access_token'; 73 | } 74 | 75 | /** 76 | * Get the Post fields for the token request. 77 | * 78 | * @param string $code 79 | * 80 | * @return array 81 | */ 82 | protected function getTokenFields($code) 83 | { 84 | return parent::getTokenFields($code) + ['grant_type' => 'authorization_code']; 85 | } 86 | 87 | 88 | /** 89 | * Get the raw user for the given access token. 90 | * 91 | * @param \Overtrue\Socialite\AccessTokenInterface $token 92 | * 93 | * @return array 94 | */ 95 | protected function getUserByToken(AccessTokenInterface $token) 96 | { 97 | $response = $this->getHttpClient() 98 | ->setUrl($this->baseUrl.'/'.$this->version.'/users/show.json') 99 | ->setQuery([ 100 | 'uid' => $token['uid'], 101 | 'access_token' => $token->getToken(), 102 | ]) 103 | ->get(['Accept' => 'application/json']); 104 | 105 | return json_decode($response->getBody(), true); 106 | } 107 | 108 | /** 109 | * Map the raw user array to a Socialite User instance. 110 | * 111 | * @param array $user 112 | * 113 | * @return \Overtrue\Socialite\User 114 | */ 115 | protected function mapUserToObject(array $user) 116 | { 117 | return new User([ 118 | 'id' => $this->arrayItem($user, 'id'), 119 | 'nickname' => $this->arrayItem($user, 'screen_name'), 120 | 'name' => $this->arrayItem($user, 'name'), 121 | 'email' => $this->arrayItem($user, 'email'), 122 | 'avatar' => $this->arrayItem($user, 'avatar_large'), 123 | ]); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/SocialiteManager.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | use Closure; 15 | use InvalidArgumentException; 16 | use EasySwoole\Http\Request; 17 | use EasySwoole\Http\Response; 18 | 19 | 20 | /** 21 | * Class SocialiteManager. 22 | */ 23 | class SocialiteManager implements FactoryInterface 24 | { 25 | /** 26 | * The configuration. 27 | * 28 | * @var \Overtrue\Socialite\Config 29 | */ 30 | protected $config; 31 | 32 | /** 33 | * The request instance. 34 | * 35 | * @var Request 36 | */ 37 | protected $request; 38 | 39 | /** 40 | * @var Response 41 | */ 42 | protected $response; 43 | 44 | /** 45 | * The registered custom driver creators. 46 | * 47 | * @var array 48 | */ 49 | protected $customCreators = []; 50 | 51 | /** 52 | * The initial drivers. 53 | * 54 | * @var array 55 | */ 56 | protected $initialDrivers = [ 57 | 'facebook' => 'Facebook', 58 | 'github' => 'GitHub', 59 | 'google' => 'Google', 60 | 'linkedin' => 'Linkedin', 61 | 'weibo' => 'Weibo', 62 | 'qq' => 'QQ', 63 | 'wechat' => 'WeChat', 64 | 'douban' => 'Douban', 65 | 'wework' => 'WeWork', 66 | 'outlook' => 'Outlook', 67 | 'douyin' => 'DouYin', 68 | 'taobao' => 'Taobao', 69 | ]; 70 | 71 | /** 72 | * The array of created "drivers". 73 | * 74 | * @var ProviderInterface[] 75 | */ 76 | protected $drivers = []; 77 | 78 | /** 79 | * SocialiteManager constructor. 80 | * 81 | * @param array $config 82 | * @param Request $request 83 | * @param Response $response 84 | */ 85 | public function __construct(array $config, Request $request,Response $response) 86 | { 87 | 88 | $this->config = new Config($config); 89 | 90 | $this->setRequest($request); 91 | $this->setResponse($response); 92 | } 93 | 94 | /** 95 | * Set config instance. 96 | * 97 | * @param \Overtrue\Socialite\Config $config 98 | * 99 | * @return $this 100 | */ 101 | public function config(Config $config) 102 | { 103 | $this->config = $config; 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * Get a driver instance. 110 | * 111 | * @param string $driver 112 | * 113 | * @return ProviderInterface 114 | */ 115 | public function driver($driver) 116 | { 117 | if (!isset($this->drivers[$driver])) { 118 | $this->drivers[$driver] = $this->createDriver($driver); 119 | } 120 | 121 | return $this->drivers[$driver]; 122 | } 123 | 124 | /** 125 | * @param Request $request 126 | * 127 | * @return $this 128 | */ 129 | public function setRequest(Request $request) 130 | { 131 | $this->request = $request; 132 | 133 | return $this; 134 | } 135 | 136 | /** 137 | * @return Request 138 | */ 139 | public function getRequest() 140 | { 141 | return $this->request ?: $this->createDefaultRequest(); 142 | } 143 | 144 | /** 145 | * @param Response $response 146 | * 147 | * @return $this 148 | */ 149 | public function setResponse(Response $response) 150 | { 151 | $this->response = $response; 152 | 153 | return $this; 154 | } 155 | 156 | /** 157 | * @return Response 158 | */ 159 | public function getResponse() 160 | { 161 | return $this->response; 162 | } 163 | 164 | /** 165 | * Create a new driver instance. 166 | * 167 | * @param string $driver 168 | * 169 | * @throws \InvalidArgumentException 170 | * 171 | * @return ProviderInterface 172 | */ 173 | protected function createDriver($driver) 174 | { 175 | if (isset($this->initialDrivers[$driver])) { 176 | $provider = $this->initialDrivers[$driver]; 177 | $provider = __NAMESPACE__.'\\Providers\\'.$provider.'Provider'; 178 | 179 | return $this->buildProvider($provider, $this->formatConfig($this->config->get($driver))); 180 | } 181 | 182 | if (isset($this->customCreators[$driver])) { 183 | return $this->callCustomCreator($driver); 184 | } 185 | 186 | throw new InvalidArgumentException("Driver [$driver] not supported."); 187 | } 188 | 189 | /** 190 | * Call a custom driver creator. 191 | * 192 | * @param string $driver 193 | * 194 | * @return ProviderInterface 195 | */ 196 | protected function callCustomCreator($driver) 197 | { 198 | return $this->customCreators[$driver]($this->config); 199 | } 200 | 201 | /** 202 | * Create default request instance. 203 | * 204 | * @return Request 205 | */ 206 | protected function createDefaultRequest() 207 | { 208 | 209 | //$request = Request::createFromGlobals(); 210 | //$session = new Session(); 211 | 212 | //$request->setSession($session); 213 | 214 | return $this->request; 215 | } 216 | 217 | /** 218 | * Register a custom driver creator Closure. 219 | * 220 | * @param string $driver 221 | * @param \Closure $callback 222 | * 223 | * @return $this 224 | */ 225 | public function extend($driver, Closure $callback) 226 | { 227 | $this->customCreators[$driver] = $callback; 228 | 229 | return $this; 230 | } 231 | 232 | /** 233 | * Get all of the created "drivers". 234 | * 235 | * @return ProviderInterface[] 236 | */ 237 | public function getDrivers() 238 | { 239 | return $this->drivers; 240 | } 241 | 242 | /** 243 | * Build an OAuth 2 provider instance. 244 | * 245 | * @param string $provider 246 | * @param array $config 247 | * 248 | * @return ProviderInterface 249 | */ 250 | public function buildProvider($provider, $config) 251 | { 252 | return new $provider( 253 | $this->getRequest(), 254 | $this->getResponse(), 255 | $config['client_id'], 256 | $config['client_secret'], 257 | $config['redirect'] 258 | ); 259 | } 260 | 261 | /** 262 | * Format the server configuration. 263 | * 264 | * @param array $config 265 | * 266 | * @return array 267 | */ 268 | public function formatConfig(array $config) 269 | { 270 | return array_merge([ 271 | 'identifier' => $config['client_id'], 272 | 'secret' => $config['client_secret'], 273 | 'callback_uri' => $config['redirect'], 274 | ], $config); 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /src/User.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | use ArrayAccess; 15 | use JsonSerializable; 16 | 17 | /** 18 | * Class User. 19 | */ 20 | class User implements ArrayAccess, UserInterface, JsonSerializable, \Serializable 21 | { 22 | use HasAttributes; 23 | 24 | /** 25 | * User constructor. 26 | * 27 | * @param array $attributes 28 | */ 29 | public function __construct(array $attributes) 30 | { 31 | $this->attributes = $attributes; 32 | } 33 | 34 | /** 35 | * Get the unique identifier for the user. 36 | * 37 | * @return string 38 | */ 39 | public function getId() 40 | { 41 | return $this->getAttribute('id'); 42 | } 43 | 44 | /** 45 | * Get the username for the user. 46 | * 47 | * @return string 48 | */ 49 | public function getUsername() 50 | { 51 | return $this->getAttribute('username', $this->getId()); 52 | } 53 | 54 | /** 55 | * Get the nickname / username for the user. 56 | * 57 | * @return string 58 | */ 59 | public function getNickname() 60 | { 61 | return $this->getAttribute('nickname'); 62 | } 63 | 64 | /** 65 | * Get the full name of the user. 66 | * 67 | * @return string 68 | */ 69 | public function getName() 70 | { 71 | return $this->getAttribute('name'); 72 | } 73 | 74 | /** 75 | * Get the e-mail address of the user. 76 | * 77 | * @return string 78 | */ 79 | public function getEmail() 80 | { 81 | return $this->getAttribute('email'); 82 | } 83 | 84 | /** 85 | * Get the avatar / image URL for the user. 86 | * 87 | * @return string 88 | */ 89 | public function getAvatar() 90 | { 91 | return $this->getAttribute('avatar'); 92 | } 93 | 94 | /** 95 | * Set the token on the user. 96 | * 97 | * @param \Overtrue\Socialite\AccessTokenInterface $token 98 | * 99 | * @return $this 100 | */ 101 | public function setToken(AccessTokenInterface $token) 102 | { 103 | $this->setAttribute('token', $token->getToken()); 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * @param string $provider 110 | * 111 | * @return $this 112 | */ 113 | public function setProviderName($provider) 114 | { 115 | $this->setAttribute('provider', $provider); 116 | 117 | return $this; 118 | } 119 | 120 | /** 121 | * @return string 122 | */ 123 | public function getProviderName() 124 | { 125 | return $this->getAttribute('provider'); 126 | } 127 | 128 | /** 129 | * Get the authorized token. 130 | * 131 | * @return \Overtrue\Socialite\AccessToken 132 | */ 133 | public function getToken() 134 | { 135 | return new AccessToken(['access_token' => $this->getAttribute('token')]); 136 | } 137 | 138 | /** 139 | * Alias of getToken(). 140 | * 141 | * @return \Overtrue\Socialite\AccessToken 142 | */ 143 | public function getAccessToken() 144 | { 145 | return $this->getToken(); 146 | } 147 | 148 | /** 149 | * Get the original attributes. 150 | * 151 | * @return array 152 | */ 153 | public function getOriginal() 154 | { 155 | return $this->getAttribute('original'); 156 | } 157 | 158 | /** 159 | * {@inheritdoc} 160 | */ 161 | public function jsonSerialize() 162 | { 163 | return $this->attributes; 164 | } 165 | 166 | public function serialize() 167 | { 168 | return serialize($this->attributes); 169 | } 170 | 171 | /** 172 | * Constructs the object. 173 | * 174 | * @see https://php.net/manual/en/serializable.unserialize.php 175 | * 176 | * @param string $serialized

177 | * The string representation of the object. 178 | *

179 | * 180 | * @since 5.1.0 181 | */ 182 | public function unserialize($serialized) 183 | { 184 | $this->attributes = \unserialize($serialized) ?? []; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/UserInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | /** 15 | * Interface UserInterface. 16 | */ 17 | interface UserInterface 18 | { 19 | /** 20 | * Get the unique identifier for the user. 21 | * 22 | * @return string 23 | */ 24 | public function getId(); 25 | 26 | /** 27 | * Get the nickname / username for the user. 28 | * 29 | * @return string 30 | */ 31 | public function getNickname(); 32 | 33 | /** 34 | * Get the full name of the user. 35 | * 36 | * @return string 37 | */ 38 | public function getName(); 39 | 40 | /** 41 | * Get the e-mail address of the user. 42 | * 43 | * @return string 44 | */ 45 | public function getEmail(); 46 | 47 | /** 48 | * Get the avatar / image URL for the user. 49 | * 50 | * @return string 51 | */ 52 | public function getAvatar(); 53 | } 54 | -------------------------------------------------------------------------------- /src/WeChatComponentInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Overtrue\Socialite; 13 | 14 | /** 15 | * Interface WeChatComponentInterface. 16 | */ 17 | interface WeChatComponentInterface 18 | { 19 | /** 20 | * Return the open-platform component app id. 21 | * 22 | * @return string 23 | */ 24 | public function getAppId(); 25 | 26 | /** 27 | * Return the open-platform component access token string. 28 | * 29 | * @return string 30 | */ 31 | public function getToken(); 32 | } 33 | -------------------------------------------------------------------------------- /tests/HttpController/Index.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'client_id' => 'xxxx', 16 | 'client_secret' => 'xxxx', 17 | 'redirect' => 'xxxx', 18 | ], 19 | ]; 20 | 21 | $socialite = new \Overtrue\Socialite\SocialiteManager($config,$this->request(),$this->response()); 22 | $socialite->driver('wechat')->redirect(); 23 | /* 24 | $config = [ 25 | 'qq' => [ 26 | 'client_id' => 'xxxx', 27 | 'client_secret' => 'xxxx', 28 | 'redirect' => 'xxxx', 29 | ], 30 | ]; 31 | 32 | $socialite = new \Overtrue\Socialite\SocialiteManager($config,$this->request(),$this->response()); 33 | $socialite->driver('qq')->redirect(); 34 | 35 | $config = [ 36 | 'weibo' => [ 37 | 'client_id' => 'xxxx', 38 | 'client_secret' => 'xxxx', 39 | 'redirect' => 'xxxx', 40 | ], 41 | ]; 42 | 43 | $socialite = new \Overtrue\Socialite\SocialiteManager($config,$this->request(),$this->response()); 44 | $socialite->driver('weibo')->redirect(); 45 | 46 | $config = [ 47 | 'github' => [ 48 | 'client_id' => 'xxxx', 49 | 'client_secret' => 'xxxx', 50 | 'redirect' => 'xxxx', 51 | ], 52 | ]; 53 | 54 | $socialite = new \Overtrue\Socialite\SocialiteManager($config,$this->request(),$this->response()); 55 | $socialite->driver('github')->redirect();*/ 56 | } 57 | 58 | 59 | function callback() 60 | { 61 | $config = [ 62 | 'wechat' => [ 63 | 'client_id' => 'xxxx', 64 | 'client_secret' => 'xxx', 65 | 'redirect' => 'xxxxxx', 66 | ], 67 | ]; 68 | 69 | $socialite = new \Overtrue\Socialite\SocialiteManager($config,$this->request(),$this->response()); 70 | $user=$socialite->driver('wechat')->user(); 71 | var_dump($user); 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /tests/index.php: -------------------------------------------------------------------------------- 1 | set([ 5 | 'worker_num'=>1 6 | ]); 7 | 8 | $http->on("start", function ($server) { 9 | echo "Swoole http server is started at http://127.0.0.1:9501\n"; 10 | }); 11 | 12 | $service = new \EasySwoole\Http\WebService(); 13 | $service->setExceptionHandler(function (\Throwable $throwable,\EasySwoole\Http\Request $request,\EasySwoole\Http\Response $response){ 14 | $response->write('error:'.$throwable->getMessage()); 15 | }); 16 | $http->on("request", function ($request, $response)use ($service) { 17 | $req = new \EasySwoole\Http\Request($request); 18 | $service->onRequest($req,new \EasySwoole\Http\Response($response)); 19 | }); 20 | 21 | $http->start(); --------------------------------------------------------------------------------