更新
This commit is contained in:
9
vendor/overtrue/socialite/.github/FUNDING.yml
vendored
Normal file
9
vendor/overtrue/socialite/.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: overtrue
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
custom: # Replace with a single custom sponsorship URL
|
||||
9
vendor/overtrue/socialite/.gitignore
vendored
Normal file
9
vendor/overtrue/socialite/.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/vendor
|
||||
composer.phar
|
||||
composer.lock
|
||||
.DS_Store
|
||||
/.idea
|
||||
Thumbs.db
|
||||
/*.php
|
||||
sftp-config.json
|
||||
.php_cs.cache
|
||||
28
vendor/overtrue/socialite/.php_cs
vendored
Normal file
28
vendor/overtrue/socialite/.php_cs
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
$header = <<<EOF
|
||||
This file is part of the overtrue/socialite.
|
||||
|
||||
(c) overtrue <i@overtrue.me>
|
||||
|
||||
This source file is subject to the MIT license that is bundled
|
||||
with this source code in the file LICENSE.
|
||||
EOF;
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
->setRiskyAllowed(true)
|
||||
->setRules(array(
|
||||
'@Symfony' => true,
|
||||
'header_comment' => array('header' => $header),
|
||||
'array_syntax' => array('syntax' => 'short'),
|
||||
'ordered_imports' => true,
|
||||
'no_useless_else' => true,
|
||||
'no_useless_return' => true,
|
||||
'php_unit_construct' => true,
|
||||
'php_unit_strict' => true,
|
||||
))
|
||||
->setFinder(
|
||||
PhpCsFixer\Finder::create()
|
||||
->exclude('vendor')
|
||||
->in(__DIR__)
|
||||
)
|
||||
;
|
||||
13
vendor/overtrue/socialite/.travis.yml
vendored
Normal file
13
vendor/overtrue/socialite/.travis.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 7.0
|
||||
- 7.1
|
||||
- 7.2
|
||||
|
||||
sudo: false
|
||||
dist: trusty
|
||||
|
||||
install: travis_retry composer install --no-interaction --prefer-source
|
||||
|
||||
script: vendor/bin/phpunit --verbose
|
||||
21
vendor/overtrue/socialite/LICENSE.txt
vendored
Normal file
21
vendor/overtrue/socialite/LICENSE.txt
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) overtrue <i@overtrue.me>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
267
vendor/overtrue/socialite/README.md
vendored
Normal file
267
vendor/overtrue/socialite/README.md
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
<h1 align="center"> Socialite</h1>
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/overtrue/socialite"><img src="https://travis-ci.org/overtrue/socialite.svg?branch=master" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/socialite"><img src="https://poser.pugx.org/overtrue/socialite/v/stable.svg" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/socialite"><img src="https://poser.pugx.org/overtrue/socialite/v/unstable.svg" alt="Latest Unstable Version"></a>
|
||||
<a href="https://scrutinizer-ci.com/g/overtrue/socialite/build-status/master"><img src="https://scrutinizer-ci.com/g/overtrue/socialite/badges/build.png?b=master" alt="Build Status"></a>
|
||||
<a href="https://scrutinizer-ci.com/g/overtrue/socialite/?branch=master"><img src="https://scrutinizer-ci.com/g/overtrue/socialite/badges/quality-score.png?b=master" alt="Scrutinizer Code Quality"></a>
|
||||
<a href="https://scrutinizer-ci.com/g/overtrue/socialite/?branch=master"><img src="https://scrutinizer-ci.com/g/overtrue/socialite/badges/coverage.png?b=master" alt="Code Coverage"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/socialite"><img src="https://poser.pugx.org/overtrue/socialite/downloads" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/overtrue/socialite"><img src="https://poser.pugx.org/overtrue/socialite/license" alt="License"></a>
|
||||
</p>
|
||||
|
||||
|
||||
<p align="center">Socialite is an OAuth2 Authentication tool. It is inspired by <a href="https://github.com/laravel/socialite">laravel/socialite</a>, You can easily use it in any PHP project.</p>
|
||||
|
||||
# Requirement
|
||||
|
||||
```
|
||||
PHP >= 5.6
|
||||
```
|
||||
# Installation
|
||||
|
||||
```shell
|
||||
$ composer require "overtrue/socialite" -vvv
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
For Laravel 5: [overtrue/laravel-socialite](https://github.com/overtrue/laravel-socialite)
|
||||
|
||||
`authorize.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Overtrue\Socialite\SocialiteManager;
|
||||
|
||||
$config = [
|
||||
'github' => [
|
||||
'client_id' => 'your-app-id',
|
||||
'client_secret' => 'your-app-secret',
|
||||
'redirect' => 'http://localhost/socialite/callback.php',
|
||||
],
|
||||
];
|
||||
|
||||
$socialite = new SocialiteManager($config);
|
||||
|
||||
$response = $socialite->driver('github')->redirect();
|
||||
|
||||
echo $response;// or $response->send();
|
||||
```
|
||||
|
||||
`callback.php`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Overtrue\Socialite\SocialiteManager;
|
||||
|
||||
$config = [
|
||||
'github' => [
|
||||
'client_id' => 'your-app-id',
|
||||
'client_secret' => 'your-app-secret',
|
||||
'redirect' => 'http://localhost/socialite/callback.php',
|
||||
],
|
||||
];
|
||||
|
||||
$socialite = new SocialiteManager($config);
|
||||
|
||||
$user = $socialite->driver('github')->user();
|
||||
|
||||
$user->getId(); // 1472352
|
||||
$user->getNickname(); // "overtrue"
|
||||
$user->getUsername(); // "overtrue"
|
||||
$user->getName(); // "安正超"
|
||||
$user->getEmail(); // "anzhengchao@gmail.com"
|
||||
$user->getProviderName(); // GitHub
|
||||
...
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
Now we support the following sites:
|
||||
|
||||
`facebook`, `github`, `google`, `linkedin`, `outlook`, `weibo`, `taobao`, `qq`, `wechat`, `douyin`, `baidu`, `feishu`, and `douban`.
|
||||
|
||||
Each driver uses the same configuration keys: `client_id`, `client_secret`, `redirect`.
|
||||
|
||||
Example:
|
||||
```
|
||||
...
|
||||
'weibo' => [
|
||||
'client_id' => 'your-app-id',
|
||||
'client_secret' => 'your-app-secret',
|
||||
'redirect' => 'http://localhost/socialite/callback.php',
|
||||
],
|
||||
...
|
||||
```
|
||||
|
||||
### Scope
|
||||
|
||||
Before redirecting the user, you may also set "scopes" on the request using the scope method. This method will overwrite all existing scopes:
|
||||
|
||||
```php
|
||||
$response = $socialite->driver('github')
|
||||
->scopes(['scope1', 'scope2'])->redirect();
|
||||
|
||||
```
|
||||
|
||||
### Redirect URL
|
||||
|
||||
You may also want to dynamicly set `redirect`,you can use the following methods to change the `redirect` URL:
|
||||
|
||||
```php
|
||||
$socialite->redirect($url);
|
||||
// or
|
||||
$socialite->withRedirectUrl($url)->redirect();
|
||||
// or
|
||||
$socialite->setRedirectUrl($url)->redirect();
|
||||
```
|
||||
|
||||
> WeChat scopes:
|
||||
- `snsapi_base`, `snsapi_userinfo` - Used to Media Platform Authentication.
|
||||
- `snsapi_login` - Used to web Authentication.
|
||||
|
||||
### Additional parameters
|
||||
|
||||
To include any optional parameters in the request, call the with method with an associative array:
|
||||
|
||||
```php
|
||||
$response = $socialite->driver('google')
|
||||
->with(['hd' => 'example.com'])->redirect();
|
||||
```
|
||||
|
||||
### User interface
|
||||
|
||||
#### Standard user api:
|
||||
|
||||
```php
|
||||
|
||||
$user = $socialite->driver('weibo')->user();
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1472352,
|
||||
"nickname": "overtrue",
|
||||
"name": "安正超",
|
||||
"email": "anzhengchao@gmail.com",
|
||||
"avatar": "https://avatars.githubusercontent.com/u/1472352?v=3",
|
||||
"original": {
|
||||
"login": "overtrue",
|
||||
"id": 1472352,
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1472352?v=3",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/overtrue",
|
||||
"html_url": "https://github.com/overtrue",
|
||||
...
|
||||
},
|
||||
"token": {
|
||||
"access_token": "5b1dc56d64fffbd052359f032716cc4e0a1cb9a0",
|
||||
"token_type": "bearer",
|
||||
"scope": "user:email"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can fetch the user attribute as a array keys like these:
|
||||
|
||||
```php
|
||||
$user['id']; // 1472352
|
||||
$user['nickname']; // "overtrue"
|
||||
$user['name']; // "安正超"
|
||||
$user['email']; // "anzhengchao@gmail.com"
|
||||
...
|
||||
```
|
||||
|
||||
Or using the method:
|
||||
|
||||
```php
|
||||
$user->getId();
|
||||
$user->getNickname();
|
||||
$user->getName();
|
||||
$user->getEmail();
|
||||
$user->getAvatar();
|
||||
$user->getOriginal();
|
||||
$user->getToken();// or $user->getAccessToken()
|
||||
$user->getProviderName(); // GitHub/Google/Facebook...
|
||||
```
|
||||
|
||||
#### Get original response from OAuth API
|
||||
|
||||
The `$user->getOriginal()` method will return an array of the API raw response.
|
||||
|
||||
#### Get access token Object
|
||||
|
||||
You can get the access token instance of current session by call `$user->getToken()` or `$user->getAccessToken()` or `$user['token']` .
|
||||
|
||||
|
||||
### Get user with access token
|
||||
|
||||
```php
|
||||
$accessToken = new AccessToken(['access_token' => $accessToken]);
|
||||
$user = $socialite->user($accessToken);
|
||||
```
|
||||
|
||||
|
||||
### Custom Session or Request instance.
|
||||
|
||||
You can set the request with your custom `Request` instance which instanceof `Symfony\Component\HttpFoundation\Request` before you call `driver` method.
|
||||
|
||||
|
||||
```php
|
||||
|
||||
$request = new Request(); // or use AnotherCustomRequest.
|
||||
|
||||
$socialite = new SocialiteManager($config, $request);
|
||||
```
|
||||
|
||||
Or set request to `SocialiteManager` instance:
|
||||
|
||||
```php
|
||||
$socialite->setRequest($request);
|
||||
```
|
||||
|
||||
You can get the request from the `SocialiteManager` instance by `getRequest()`:
|
||||
|
||||
```php
|
||||
$request = $socialite->getRequest();
|
||||
```
|
||||
|
||||
#### Set custom session manager.
|
||||
|
||||
By default, the `SocialiteManager` uses the `Symfony\Component\HttpFoundation\Session\Session` instance as session manager, you can change it as follows:
|
||||
|
||||
```php
|
||||
$session = new YourCustomSessionManager();
|
||||
$socialite->getRequest()->setSession($session);
|
||||
```
|
||||
|
||||
> Your custom session manager must be implement the [`Symfony\Component\HttpFoundation\Session\SessionInterface`](http://api.symfony.com/3.0/Symfony/Component/HttpFoundation/Session/SessionInterface.html).
|
||||
|
||||
Enjoy it! :heart:
|
||||
|
||||
# Reference
|
||||
|
||||
- [Google - OpenID Connect](https://developers.google.com/identity/protocols/OpenIDConnect)
|
||||
- [Facebook - Graph API](https://developers.facebook.com/docs/graph-api)
|
||||
- [Linkedin - Authenticating with OAuth 2.0](https://developer.linkedin.com/docs/oauth2)
|
||||
- [微博 - OAuth 2.0 授权机制说明](http://open.weibo.com/wiki/%E6%8E%88%E6%9D%83%E6%9C%BA%E5%88%B6%E8%AF%B4%E6%98%8E)
|
||||
- [QQ - OAuth 2.0 登录QQ](http://wiki.connect.qq.com/oauth2-0%E7%AE%80%E4%BB%8B)
|
||||
- [微信公众平台 - OAuth文档](http://mp.weixin.qq.com/wiki/9/01f711493b5a02f24b04365ac5d8fd95.html)
|
||||
- [微信开放平台 - 网站应用微信登录开发指南](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN)
|
||||
- [微信开放平台 - 代公众号发起网页授权](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419318590&token=&lang=zh_CN)
|
||||
- [豆瓣 - OAuth 2.0 授权机制说明](http://developers.douban.com/wiki/?title=oauth2)
|
||||
- [抖音 - 网站应用开发指南](http://open.douyin.com/platform/doc)
|
||||
- [飞书 - 授权说明](https://open.feishu.cn/document/ukTMukTMukTM/uMTNz4yM1MjLzUzM)
|
||||
|
||||
## PHP 扩展包开发
|
||||
|
||||
> 想知道如何从零开始构建 PHP 扩展包?
|
||||
>
|
||||
> 请关注我的实战课程,我会在此课程中分享一些扩展开发经验 —— [《PHP 扩展包实战教程 - 从入门到发布》](https://learnku.com/courses/creating-package)
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
34
vendor/overtrue/socialite/composer.json
vendored
Normal file
34
vendor/overtrue/socialite/composer.json
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "overtrue/socialite",
|
||||
"description": "A collection of OAuth 2 packages that extracts from laravel/socialite.",
|
||||
"keywords": [
|
||||
"OAuth",
|
||||
"social",
|
||||
"login",
|
||||
"Weibo",
|
||||
"WeChat",
|
||||
"QQ"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Overtrue\\Socialite\\": "src/"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6",
|
||||
"guzzlehttp/guzzle": "^5.0|^6.0|^7.0",
|
||||
"symfony/http-foundation": "^2.7|^3.0|^4.0|^5.0",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~1.2",
|
||||
"phpunit/phpunit": "^6.0|^7.0|^8.0|^9.0"
|
||||
},
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "overtrue",
|
||||
"email": "anzhengchao@gmail.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
18
vendor/overtrue/socialite/phpunit.xml
vendored
Normal file
18
vendor/overtrue/socialite/phpunit.xml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
bootstrap="vendor/autoload.php"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Package Test Suite">
|
||||
<directory suffix=".php">./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
84
vendor/overtrue/socialite/src/AccessToken.php
vendored
Normal file
84
vendor/overtrue/socialite/src/AccessToken.php
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
use ArrayAccess;
|
||||
use InvalidArgumentException;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* Class AccessToken.
|
||||
*/
|
||||
class AccessToken implements AccessTokenInterface, ArrayAccess, JsonSerializable
|
||||
{
|
||||
use HasAttributes;
|
||||
|
||||
/**
|
||||
* AccessToken constructor.
|
||||
*
|
||||
* @param array $attributes
|
||||
*/
|
||||
public function __construct(array $attributes)
|
||||
{
|
||||
if (empty($attributes['access_token'])) {
|
||||
throw new InvalidArgumentException('The key "access_token" could not be empty.');
|
||||
}
|
||||
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the access token string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return $this->getAttribute('access_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the refresh token string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRefreshToken()
|
||||
{
|
||||
return $this->getAttribute('refresh_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set refresh token into this object.
|
||||
*
|
||||
* @param string $token
|
||||
*/
|
||||
public function setRefreshToken($token)
|
||||
{
|
||||
$this->setAttribute('refresh_token', $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return strval($this->getAttribute('access_token', ''));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->getToken();
|
||||
}
|
||||
}
|
||||
25
vendor/overtrue/socialite/src/AccessTokenInterface.php
vendored
Normal file
25
vendor/overtrue/socialite/src/AccessTokenInterface.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
/**
|
||||
* Interface AccessTokenInterface.
|
||||
*/
|
||||
interface AccessTokenInterface
|
||||
{
|
||||
/**
|
||||
* Return the access token string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getToken();
|
||||
}
|
||||
35
vendor/overtrue/socialite/src/AuthorizeFailedException.php
vendored
Normal file
35
vendor/overtrue/socialite/src/AuthorizeFailedException.php
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
class AuthorizeFailedException extends \RuntimeException
|
||||
{
|
||||
/**
|
||||
* Response body.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $body;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $message
|
||||
* @param array $body
|
||||
*/
|
||||
public function __construct($message, $body)
|
||||
{
|
||||
parent::__construct($message, -1);
|
||||
|
||||
$this->body = $body;
|
||||
}
|
||||
}
|
||||
180
vendor/overtrue/socialite/src/Config.php
vendored
Normal file
180
vendor/overtrue/socialite/src/Config.php
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
use ArrayAccess;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Class Config.
|
||||
*/
|
||||
class Config implements ArrayAccess
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* Config constructor.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(array $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item from an array using "dot" notation.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
$config = $this->config;
|
||||
|
||||
if (is_null($key)) {
|
||||
return $config;
|
||||
}
|
||||
if (isset($config[$key])) {
|
||||
return $config[$key];
|
||||
}
|
||||
foreach (explode('.', $key) as $segment) {
|
||||
if (!is_array($config) || !array_key_exists($segment, $config)) {
|
||||
return $default;
|
||||
}
|
||||
$config = $config[$segment];
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an array item to a given value using "dot" notation.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function set($key, $value)
|
||||
{
|
||||
if (is_null($key)) {
|
||||
throw new InvalidArgumentException('Invalid config key.');
|
||||
}
|
||||
|
||||
$keys = explode('.', $key);
|
||||
$config = &$this->config;
|
||||
|
||||
while (count($keys) > 1) {
|
||||
$key = array_shift($keys);
|
||||
if (!isset($config[$key]) || !is_array($config[$key])) {
|
||||
$config[$key] = [];
|
||||
}
|
||||
$config = &$config[$key];
|
||||
}
|
||||
|
||||
$config[array_shift($keys)] = $value;
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given configuration value exists.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has($key)
|
||||
{
|
||||
return (bool) $this->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a offset exists.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetexists.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* An offset to check for.
|
||||
* </p>
|
||||
*
|
||||
* @return bool true on success or false on failure.
|
||||
* </p>
|
||||
* <p>
|
||||
* The return value will be casted to boolean if non-boolean was returned
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return array_key_exists($offset, $this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to retrieve.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetget.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to retrieve.
|
||||
* </p>
|
||||
*
|
||||
* @return mixed Can return all value types
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->get($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to set.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetset.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to assign the value to.
|
||||
* </p>
|
||||
* @param mixed $value <p>
|
||||
* The value to set.
|
||||
* </p>
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->set($offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset to unset.
|
||||
*
|
||||
* @see http://php.net/manual/en/arrayaccess.offsetunset.php
|
||||
*
|
||||
* @param mixed $offset <p>
|
||||
* The offset to unset.
|
||||
* </p>
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
$this->set($offset, null);
|
||||
}
|
||||
}
|
||||
27
vendor/overtrue/socialite/src/FactoryInterface.php
vendored
Normal file
27
vendor/overtrue/socialite/src/FactoryInterface.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
/**
|
||||
* Interface FactoryInterface.
|
||||
*/
|
||||
interface FactoryInterface
|
||||
{
|
||||
/**
|
||||
* Get an OAuth provider implementation.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @return \Overtrue\Socialite\ProviderInterface
|
||||
*/
|
||||
public function driver($driver);
|
||||
}
|
||||
135
vendor/overtrue/socialite/src/HasAttributes.php
vendored
Normal file
135
vendor/overtrue/socialite/src/HasAttributes.php
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
/**
|
||||
* Trait HasAttributes.
|
||||
*/
|
||||
trait HasAttributes
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [];
|
||||
|
||||
/**
|
||||
* Return the attributes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAttributes()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the extra attribute.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttribute($name, $default = null)
|
||||
{
|
||||
return isset($this->attributes[$name]) ? $this->attributes[$name] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set extra attributes.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAttribute($name, $value)
|
||||
{
|
||||
$this->attributes[$name] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the given array onto the user's properties.
|
||||
*
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function merge(array $attributes)
|
||||
{
|
||||
$this->attributes = array_merge($this->attributes, $attributes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetExists($offset)
|
||||
{
|
||||
return array_key_exists($offset, $this->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
return $this->getAttribute($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
{
|
||||
$this->setAttribute($offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
{
|
||||
unset($this->attributes[$offset]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __get($property)
|
||||
{
|
||||
return $this->getAttribute($property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return $this->getAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSON.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toJSON()
|
||||
{
|
||||
return json_encode($this->getAttributes(), JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
}
|
||||
16
vendor/overtrue/socialite/src/InvalidArgumentException.php
vendored
Normal file
16
vendor/overtrue/socialite/src/InvalidArgumentException.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
class InvalidArgumentException extends \InvalidArgumentException
|
||||
{
|
||||
}
|
||||
16
vendor/overtrue/socialite/src/InvalidStateException.php
vendored
Normal file
16
vendor/overtrue/socialite/src/InvalidStateException.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
class InvalidStateException extends \InvalidArgumentException
|
||||
{
|
||||
}
|
||||
31
vendor/overtrue/socialite/src/ProviderInterface.php
vendored
Normal file
31
vendor/overtrue/socialite/src/ProviderInterface.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
interface ProviderInterface
|
||||
{
|
||||
/**
|
||||
* Redirect the user to the authentication page for the provider.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
*/
|
||||
public function redirect();
|
||||
|
||||
/**
|
||||
* Get the User instance for the authenticated user.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
public function user(AccessTokenInterface $token = null);
|
||||
}
|
||||
585
vendor/overtrue/socialite/src/Providers/AbstractProvider.php
vendored
Normal file
585
vendor/overtrue/socialite/src/Providers/AbstractProvider.php
vendored
Normal file
@@ -0,0 +1,585 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Overtrue\Socialite\AccessToken;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\AuthorizeFailedException;
|
||||
use Overtrue\Socialite\Config;
|
||||
use Overtrue\Socialite\InvalidStateException;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Class AbstractProvider.
|
||||
*/
|
||||
abstract class AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* Provider name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The HTTP request instance.
|
||||
*
|
||||
* @var \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Driver config.
|
||||
*
|
||||
* @var Config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The client ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $clientId;
|
||||
|
||||
/**
|
||||
* The client secret.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $clientSecret;
|
||||
|
||||
/**
|
||||
* @var \Overtrue\Socialite\AccessTokenInterface
|
||||
*/
|
||||
protected $accessToken;
|
||||
|
||||
/**
|
||||
* The redirect URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $redirectUrl;
|
||||
|
||||
/**
|
||||
* The custom parameters to be sent with the request.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parameters = [];
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [];
|
||||
|
||||
/**
|
||||
* The separating character for the requested scopes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $scopeSeparator = ',';
|
||||
|
||||
/**
|
||||
* The type of the encoding in the query.
|
||||
*
|
||||
* @var int Can be either PHP_QUERY_RFC3986 or PHP_QUERY_RFC1738
|
||||
*/
|
||||
protected $encodingType = PHP_QUERY_RFC1738;
|
||||
|
||||
/**
|
||||
* Indicates if the session state should be utilized.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $stateless = false;
|
||||
|
||||
/**
|
||||
* The options for guzzle\client.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $guzzleOptions = ['http_errors' => false];
|
||||
|
||||
/**
|
||||
* Create a new provider instance.
|
||||
*
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct(Request $request, $config)
|
||||
{
|
||||
// 兼容处理
|
||||
if (!\is_array($config)) {
|
||||
$config = [
|
||||
'client_id' => \func_get_arg(1),
|
||||
'client_secret' => \func_get_arg(2),
|
||||
'redirect' => \func_get_arg(3) ?: null,
|
||||
];
|
||||
}
|
||||
$this->config = new Config($config);
|
||||
$this->request = $request;
|
||||
$this->clientId = $config['client_id'];
|
||||
$this->clientSecret = $config['client_secret'];
|
||||
$this->redirectUrl = isset($config['redirect']) ? $config['redirect'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getAuthUrl($state);
|
||||
|
||||
/**
|
||||
* Get the token URL for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function getTokenUrl();
|
||||
|
||||
/**
|
||||
* Get the raw user for the given access token.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function getUserByToken(AccessTokenInterface $token);
|
||||
|
||||
/**
|
||||
* Map the raw user array to a Socialite User instance.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
abstract protected function mapUserToObject(array $user);
|
||||
|
||||
/**
|
||||
* Redirect the user of the application to the provider's authentication screen.
|
||||
*
|
||||
* @param string $redirectUrl
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse
|
||||
*/
|
||||
public function redirect($redirectUrl = null)
|
||||
{
|
||||
$state = null;
|
||||
|
||||
if (!is_null($redirectUrl)) {
|
||||
$this->redirectUrl = $redirectUrl;
|
||||
}
|
||||
|
||||
if ($this->usesState()) {
|
||||
$state = $this->makeState();
|
||||
}
|
||||
|
||||
return new RedirectResponse($this->getAuthUrl($state));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function user(AccessTokenInterface $token = null)
|
||||
{
|
||||
if (is_null($token) && $this->hasInvalidState()) {
|
||||
throw new InvalidStateException();
|
||||
}
|
||||
|
||||
$token = $token ?: $this->getAccessToken($this->getCode());
|
||||
|
||||
$user = $this->getUserByToken($token);
|
||||
|
||||
$user = $this->mapUserToObject($user)->merge(['original' => $user]);
|
||||
|
||||
return $user->setToken($token)->setProviderName($this->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set redirect url.
|
||||
*
|
||||
* @param string $redirectUrl
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRedirectUrl($redirectUrl)
|
||||
{
|
||||
$this->redirectUrl = $redirectUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set redirect url.
|
||||
*
|
||||
* @param string $redirectUrl
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function withRedirectUrl($redirectUrl)
|
||||
{
|
||||
$this->redirectUrl = $redirectUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the redirect url.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRedirectUrl()
|
||||
{
|
||||
return $this->redirectUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $accessToken
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAccessToken(AccessTokenInterface $accessToken)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessTokenInterface
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
if ($this->accessToken) {
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
$guzzleVersion = \defined(ClientInterface::class.'::VERSION') ? \constant(ClientInterface::class.'::VERSION') : 7;
|
||||
|
||||
$postKey = (1 === version_compare($guzzleVersion, '6')) ? 'form_params' : 'body';
|
||||
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'headers' => ['Accept' => 'application/json'],
|
||||
$postKey => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scopes of the requested access.
|
||||
*
|
||||
* @param array $scopes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function scopes(array $scopes)
|
||||
{
|
||||
$this->scopes = $scopes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the request instance.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequest(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the request instance.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that the provider should operate as stateless.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function stateless()
|
||||
{
|
||||
$this->stateless = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the custom parameters of the request.
|
||||
*
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function with(array $parameters)
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ReflectionException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
if (empty($this->name)) {
|
||||
$this->name = strstr((new \ReflectionClass(get_class($this)))->getShortName(), 'Provider', true);
|
||||
}
|
||||
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getConfig()
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function buildAuthUrlFromBase($url, $state)
|
||||
{
|
||||
return $url.'?'.http_build_query($this->getCodeFields($state), '', '&', $this->encodingType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the GET parameters for the code request.
|
||||
*
|
||||
* @param string|null $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getCodeFields($state = null)
|
||||
{
|
||||
$fields = array_merge([
|
||||
'client_id' => $this->config['client_id'],
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
'response_type' => 'code',
|
||||
], $this->parameters);
|
||||
|
||||
if ($this->usesState()) {
|
||||
$fields['state'] = $state;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the given scopes.
|
||||
*
|
||||
* @param array $scopes
|
||||
* @param string $scopeSeparator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function formatScopes(array $scopes, $scopeSeparator)
|
||||
{
|
||||
return implode($scopeSeparator, $scopes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current request / session has a mismatching "state".
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasInvalidState()
|
||||
{
|
||||
if ($this->isStateless()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$state = $this->request->getSession()->get('state');
|
||||
|
||||
return !(strlen($state) > 0 && $this->request->get('state') === $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the POST fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return [
|
||||
'client_id' => $this->getConfig()->get('client_id'),
|
||||
'client_secret' => $this->getConfig()->get('client_secret'),
|
||||
'code' => $code,
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token from the token response body.
|
||||
*
|
||||
* @param \Psr\Http\Message\StreamInterface|array $body
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessTokenInterface
|
||||
*/
|
||||
protected function parseAccessToken($body)
|
||||
{
|
||||
if (!is_array($body)) {
|
||||
$body = json_decode($body, true);
|
||||
}
|
||||
|
||||
if (empty($body['access_token'])) {
|
||||
throw new AuthorizeFailedException('Authorize Failed: '.json_encode($body, JSON_UNESCAPED_UNICODE), $body);
|
||||
}
|
||||
|
||||
return new AccessToken($body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the code from the request.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getCode()
|
||||
{
|
||||
return $this->request->get('code');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a fresh instance of the Guzzle HTTP client.
|
||||
*
|
||||
* @return \GuzzleHttp\Client
|
||||
*/
|
||||
protected function getHttpClient()
|
||||
{
|
||||
return new Client(self::$guzzleOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set options for Guzzle HTTP client.
|
||||
*
|
||||
* @param array $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function setGuzzleOptions($config = [])
|
||||
{
|
||||
return self::$guzzleOptions = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the provider is operating with state.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function usesState()
|
||||
{
|
||||
return !$this->stateless;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the provider is operating as stateless.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isStateless()
|
||||
{
|
||||
return !$this->request->hasSession() || $this->stateless;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array item by key.
|
||||
*
|
||||
* @param array $array
|
||||
* @param string $key
|
||||
* @param mixed $default
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function arrayItem(array $array, $key, $default = null)
|
||||
{
|
||||
if (is_null($key)) {
|
||||
return $array;
|
||||
}
|
||||
|
||||
if (isset($array[$key])) {
|
||||
return $array[$key];
|
||||
}
|
||||
|
||||
foreach (explode('.', $key) as $segment) {
|
||||
if (!is_array($array) || !array_key_exists($segment, $array)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$array = $array[$segment];
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put state to session storage and return it.
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
protected function makeState()
|
||||
{
|
||||
if (!$this->request->hasSession()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$state = sha1(uniqid(mt_rand(1, 1000000), true));
|
||||
$session = $this->request->getSession();
|
||||
|
||||
if (is_callable([$session, 'put'])) {
|
||||
$session->put('state', $state);
|
||||
} elseif (is_callable([$session, 'set'])) {
|
||||
$session->set('state', $state);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
}
|
||||
134
vendor/overtrue/socialite/src/Providers/BaiduProvider.php
vendored
Normal file
134
vendor/overtrue/socialite/src/Providers/BaiduProvider.php
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class BaiduProvider.
|
||||
*
|
||||
* @see https://developer.baidu.com/wiki/index.php?title=docs/oauth [OAuth 2.0 授权机制说明]
|
||||
*/
|
||||
class BaiduProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base url of Weibo API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://openapi.baidu.com';
|
||||
|
||||
/**
|
||||
* The API version for the request.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version = '2.0';
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [''];
|
||||
|
||||
/**
|
||||
* The uid of user authorized.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $uid;
|
||||
|
||||
protected $display = 'popup';
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth/'.$this->version.'/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getCodeFields($state = null)
|
||||
{
|
||||
return array_merge([
|
||||
'response_type' => 'code',
|
||||
'client_id' => $this->getConfig()->get('client_id'),
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
'display' => $this->display,
|
||||
], $this->parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token URL for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/oauth/'.$this->version.'/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Post fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw user for the given access token.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/rest/'.$this->version.'/passport/users/getInfo', [
|
||||
'query' => [
|
||||
'access_token' => $token->getToken(),
|
||||
],
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the raw user array to a Socialite User instance.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
$realname = $this->arrayItem($user, 'realname');
|
||||
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'userid'),
|
||||
'nickname' => empty($realname) ? '' : $realname,
|
||||
'name' => $this->arrayItem($user, 'username'),
|
||||
'email' => '',
|
||||
'avatar' => $this->arrayItem($user, 'portrait'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
169
vendor/overtrue/socialite/src/Providers/DouYinProvider.php
vendored
Normal file
169
vendor/overtrue/socialite/src/Providers/DouYinProvider.php
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessToken;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class DouYinProvider.
|
||||
*
|
||||
* @author haoliang@qiyuankeji.vip
|
||||
*
|
||||
* @see http://open.douyin.com/platform
|
||||
*/
|
||||
class DouYinProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* 抖音接口域名.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://open.douyin.com';
|
||||
|
||||
/**
|
||||
* 应用授权作用域.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['user_info'];
|
||||
|
||||
/**
|
||||
* 获取登录页面地址.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/platform/oauth/connect', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权码接口参数.
|
||||
*
|
||||
* @param string|null $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCodeFields($state = null)
|
||||
{
|
||||
$fields = [
|
||||
'client_key' => $this->getConfig()->get('client_id'),
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
'response_type' => 'code',
|
||||
];
|
||||
|
||||
if ($this->usesState()) {
|
||||
$fields['state'] = $state;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token地址.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/oauth/access_token';
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过code获取access_token.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->getTokenUrl(), [
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取access_token接口参数.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return [
|
||||
'client_key' => $this->getConfig()->get('client_id'),
|
||||
'client_secret' => $this->getConfig()->get('client_secret'),
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化token.
|
||||
*
|
||||
* @param \Psr\Http\Message\StreamInterface|array $body
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessTokenInterface
|
||||
*/
|
||||
protected function parseAccessToken($body)
|
||||
{
|
||||
if (!is_array($body)) {
|
||||
$body = json_decode($body, true);
|
||||
}
|
||||
|
||||
if (empty($body['data']['access_token'])) {
|
||||
throw new AuthorizeFailedException('Authorize Failed: '.json_encode($body, JSON_UNESCAPED_UNICODE), $body);
|
||||
}
|
||||
|
||||
return new AccessToken($body['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过token 获取用户信息.
|
||||
*
|
||||
* @param AccessTokenInterface $token
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$userUrl = $this->baseUrl.'/oauth/userinfo/';
|
||||
|
||||
$response = $this->getHttpClient()->get(
|
||||
$userUrl,
|
||||
[
|
||||
'query' => [
|
||||
'access_token' => $token->getToken(),
|
||||
'open_id' => $token['open_id'],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化用户信息.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'open_id'),
|
||||
'username' => $this->arrayItem($user, 'nickname'),
|
||||
'nickname' => $this->arrayItem($user, 'nickname'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
88
vendor/overtrue/socialite/src/Providers/DoubanProvider.php
vendored
Normal file
88
vendor/overtrue/socialite/src/Providers/DoubanProvider.php
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class DoubanProvider.
|
||||
*
|
||||
* @see http://developers.douban.com/wiki/?title=oauth2 [使用 OAuth 2.0 访问豆瓣 API]
|
||||
*/
|
||||
class DoubanProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://www.douban.com/service/auth2/auth', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'https://www.douban.com/service/auth2/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get('https://api.douban.com/v2/user/~me', [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '.$token->getToken(),
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'nickname' => $this->arrayItem($user, 'name'),
|
||||
'name' => $this->arrayItem($user, 'name'),
|
||||
'avatar' => $this->arrayItem($user, 'large_avatar'),
|
||||
'email' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'form_params' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody()->getContents());
|
||||
}
|
||||
}
|
||||
168
vendor/overtrue/socialite/src/Providers/FacebookProvider.php
vendored
Normal file
168
vendor/overtrue/socialite/src/Providers/FacebookProvider.php
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class FacebookProvider.
|
||||
*
|
||||
* @see https://developers.facebook.com/docs/graph-api [Facebook - Graph API]
|
||||
*/
|
||||
class FacebookProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base Facebook Graph URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $graphUrl = 'https://graph.facebook.com';
|
||||
|
||||
/**
|
||||
* The Graph API version for the request.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version = 'v3.3';
|
||||
|
||||
/**
|
||||
* The user fields being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fields = ['first_name', 'last_name', 'email', 'gender', 'verified'];
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['email'];
|
||||
|
||||
/**
|
||||
* Display the dialog in a popup view.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $popup = false;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://www.facebook.com/'.$this->version.'/dialog/oauth', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->graphUrl.'/oauth/access_token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->getTokenUrl(), [
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$appSecretProof = hash_hmac('sha256', $token->getToken(), $this->getConfig()->get('client_secret'));
|
||||
|
||||
$response = $this->getHttpClient()->get($this->graphUrl.'/'.$this->version.'/me?access_token='.$token.'&appsecret_proof='.$appSecretProof.'&fields='.implode(',', $this->fields), [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
$userId = $this->arrayItem($user, 'id');
|
||||
$avatarUrl = $this->graphUrl.'/'.$this->version.'/'.$userId.'/picture';
|
||||
|
||||
$firstName = $this->arrayItem($user, 'first_name');
|
||||
$lastName = $this->arrayItem($user, 'last_name');
|
||||
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'nickname' => null,
|
||||
'name' => $firstName.' '.$lastName,
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
'avatar' => $userId ? $avatarUrl.'?type=normal' : null,
|
||||
'avatar_original' => $userId ? $avatarUrl.'?width=1920' : null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getCodeFields($state = null)
|
||||
{
|
||||
$fields = parent::getCodeFields($state);
|
||||
|
||||
if ($this->popup) {
|
||||
$fields['display'] = 'popup';
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user fields to request from Facebook.
|
||||
*
|
||||
* @param array $fields
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function fields(array $fields)
|
||||
{
|
||||
$this->fields = $fields;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dialog to be displayed as a popup.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function asPopup()
|
||||
{
|
||||
$this->popup = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
192
vendor/overtrue/socialite/src/Providers/FeiShuProvider.php
vendored
Normal file
192
vendor/overtrue/socialite/src/Providers/FeiShuProvider.php
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessToken;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\AuthorizeFailedException;
|
||||
use Overtrue\Socialite\InvalidStateException;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class FeiShuProvider.
|
||||
*
|
||||
* @author qijian.song@show.world
|
||||
*
|
||||
* @see https://open.feishu.cn/
|
||||
*/
|
||||
class FeiShuProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* 飞书接口域名.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://open.feishu.cn';
|
||||
|
||||
/**
|
||||
* 应用授权作用域.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['user_info'];
|
||||
|
||||
/**
|
||||
* 获取登录页面地址.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/open-apis/authen/v1/index', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权码接口参数.
|
||||
*
|
||||
* @param string|null $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getCodeFields($state = null)
|
||||
{
|
||||
$fields = [
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'app_id' => $this->getConfig()->get('client_id'),
|
||||
];
|
||||
|
||||
if ($this->usesState()) {
|
||||
$fields['state'] = $state;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 app_access_token 地址.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/open-apis/auth/v3/app_access_token/internal';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 app_access_token.
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code = '')
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'headers' => ['Content-Type' => 'application/json'],
|
||||
'json' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 app_access_token 接口参数.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return [
|
||||
'app_id' => $this->getConfig()->get('client_id'),
|
||||
'app_secret' => $this->getConfig()->get('client_secret'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化 token.
|
||||
*
|
||||
* @param \Psr\Http\Message\StreamInterface|array $body
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessTokenInterface
|
||||
*/
|
||||
protected function parseAccessToken($body)
|
||||
{
|
||||
if (!is_array($body)) {
|
||||
$body = json_decode($body, true);
|
||||
}
|
||||
|
||||
if (empty($body['app_access_token'])) {
|
||||
throw new AuthorizeFailedException('Authorize Failed: '.json_encode($body, JSON_UNESCAPED_UNICODE), $body);
|
||||
}
|
||||
$data['access_token'] = $body['app_access_token'];
|
||||
|
||||
return new AccessToken($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息.
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function user(AccessTokenInterface $token = null)
|
||||
{
|
||||
if (is_null($token) && $this->hasInvalidState()) {
|
||||
throw new InvalidStateException();
|
||||
}
|
||||
|
||||
$token = $token ?: $this->getAccessToken();
|
||||
|
||||
$user = $this->getUserByToken($token, $this->getCode());
|
||||
$user = $this->mapUserToObject($user)->merge(['original' => $user]);
|
||||
|
||||
return $user->setToken($token)->setProviderName($this->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 token 获取用户信息.
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$userUrl = $this->baseUrl.'/open-apis/authen/v1/access_token';
|
||||
|
||||
$response = $this->getHttpClient()->post(
|
||||
$userUrl,
|
||||
[
|
||||
'json' => [
|
||||
'app_access_token' => $token->getToken(),
|
||||
'code' => $this->getCode(),
|
||||
'grant_type' => 'authorization_code',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$result = json_decode($response->getBody(), true);
|
||||
|
||||
return $result['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化用户信息.
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'open_id'),
|
||||
'username' => $this->arrayItem($user, 'name'),
|
||||
'nickname' => $this->arrayItem($user, 'name'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar_url'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
126
vendor/overtrue/socialite/src/Providers/GitHubProvider.php
vendored
Normal file
126
vendor/overtrue/socialite/src/Providers/GitHubProvider.php
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Exception;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class GitHubProvider.
|
||||
*/
|
||||
class GitHubProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['user:email'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://github.com/login/oauth/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'https://github.com/login/oauth/access_token';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$userUrl = 'https://api.github.com/user';
|
||||
|
||||
$response = $this->getHttpClient()->get(
|
||||
$userUrl,
|
||||
$this->createAuthorizationHeaders($token)
|
||||
);
|
||||
|
||||
$user = json_decode($response->getBody(), true);
|
||||
|
||||
if (in_array('user:email', $this->scopes)) {
|
||||
$user['email'] = $this->getEmailByToken($token);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the email for the given access token.
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function getEmailByToken($token)
|
||||
{
|
||||
$emailsUrl = 'https://api.github.com/user/emails';
|
||||
|
||||
try {
|
||||
$response = $this->getHttpClient()->get(
|
||||
$emailsUrl,
|
||||
$this->createAuthorizationHeaders($token)
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (json_decode($response->getBody(), true) as $email) {
|
||||
if ($email['primary'] && $email['verified']) {
|
||||
return $email['email'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'username' => $this->arrayItem($user, 'login'),
|
||||
'nickname' => $this->arrayItem($user, 'login'),
|
||||
'name' => $this->arrayItem($user, 'name'),
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar_url'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default options for an HTTP request.
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function createAuthorizationHeaders(string $token)
|
||||
{
|
||||
return [
|
||||
'headers' => [
|
||||
'Accept' => 'application/vnd.github.v3+json',
|
||||
'Authorization' => sprintf('token %s', $token),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
119
vendor/overtrue/socialite/src/Providers/GoogleProvider.php
vendored
Normal file
119
vendor/overtrue/socialite/src/Providers/GoogleProvider.php
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class GoogleProvider.
|
||||
*
|
||||
* @see https://developers.google.com/identity/protocols/OpenIDConnect [OpenID Connect]
|
||||
*/
|
||||
class GoogleProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The separating character for the requested scopes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $scopeSeparator = ' ';
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = [
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://accounts.google.com/o/oauth2/v2/auth', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'https://www.googleapis.com/oauth2/v4/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$guzzleVersion = \defined(ClientInterface::class.'::VERSION') ? \constant(ClientInterface::class.'::VERSION') : 7;
|
||||
$postKey = (1 === version_compare($guzzleVersion, '6')) ? 'form_params' : 'body';
|
||||
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
$postKey => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the POST fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get('https://www.googleapis.com/userinfo/v2/me', [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$token->getToken(),
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'username' => $this->arrayItem($user, 'email'),
|
||||
'nickname' => $this->arrayItem($user, 'name'),
|
||||
'name' => $this->arrayItem($user, 'name'),
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
'avatar' => $this->arrayItem($user, 'picture'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
181
vendor/overtrue/socialite/src/Providers/LinkedinProvider.php
vendored
Normal file
181
vendor/overtrue/socialite/src/Providers/LinkedinProvider.php
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class LinkedinProvider.
|
||||
*
|
||||
* @see https://developer.linkedin.com/docs/oauth2 [Authenticating with OAuth 2.0]
|
||||
*/
|
||||
class LinkedinProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['r_liteprofile', 'r_emailaddress'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://www.linkedin.com/oauth/v2/authorization', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()
|
||||
->post($this->getTokenUrl(), ['form_params' => $this->getTokenFields($code)]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'https://www.linkedin.com/oauth/v2/accessToken';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the POST fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$basicProfile = $this->getBasicProfile($token);
|
||||
$emailAddress = $this->getEmailAddress($token);
|
||||
|
||||
return array_merge($basicProfile, $emailAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the basic profile fields for the user.
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getBasicProfile($token)
|
||||
{
|
||||
$url = 'https://api.linkedin.com/v2/me?projection=(id,firstName,lastName,profilePicture(displayImage~:playableStreams))';
|
||||
|
||||
$response = $this->getHttpClient()->get($url, [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
'X-RestLi-Protocol-Version' => '2.0.0',
|
||||
],
|
||||
]);
|
||||
|
||||
return (array) json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the email address for the user.
|
||||
*
|
||||
* @param string $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getEmailAddress($token)
|
||||
{
|
||||
$url = 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))';
|
||||
|
||||
$response = $this->getHttpClient()->get($url, [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
'X-RestLi-Protocol-Version' => '2.0.0',
|
||||
],
|
||||
]);
|
||||
|
||||
return (array) $this->arrayItem(json_decode($response->getBody(), true), 'elements.0.handle~');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
$preferredLocale = $this->arrayItem($user, 'firstName.preferredLocale.language').'_'.$this->arrayItem($user, 'firstName.preferredLocale.country');
|
||||
$firstName = $this->arrayItem($user, 'firstName.localized.'.$preferredLocale);
|
||||
$lastName = $this->arrayItem($user, 'lastName.localized.'.$preferredLocale);
|
||||
$name = $firstName.' '.$lastName;
|
||||
|
||||
$images = (array) $this->arrayItem($user, 'profilePicture.displayImage~.elements', []);
|
||||
$avatars = array_filter($images, function ($image) {
|
||||
return $image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] === 100;
|
||||
});
|
||||
$avatar = array_shift($avatars);
|
||||
$originalAvatars = array_filter($images, function ($image) {
|
||||
return $image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] === 800;
|
||||
});
|
||||
$originalAvatar = array_shift($originalAvatars);
|
||||
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'nickname' => $name,
|
||||
'name' => $name,
|
||||
'email' => $this->arrayItem($user, 'emailAddress'),
|
||||
'avatar' => $avatar ? $this->arrayItem($avatar, 'identifiers.0.identifier') : null,
|
||||
'avatar_original' => $originalAvatar ? $this->arrayItem($originalAvatar, 'identifiers.0.identifier') : null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the user fields to request from LinkedIn.
|
||||
*
|
||||
* @param array $fields
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function fields(array $fields)
|
||||
{
|
||||
$this->fields = $fields;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the provider is operating as stateless.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isStateless()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
89
vendor/overtrue/socialite/src/Providers/OutlookProvider.php
vendored
Normal file
89
vendor/overtrue/socialite/src/Providers/OutlookProvider.php
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class OutlookProvider.
|
||||
*/
|
||||
class OutlookProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scopes = ['User.Read'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $scopeSeparator = ' ';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://login.microsoftonline.com/common/oauth2/v2.0/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get(
|
||||
'https://graph.microsoft.com/v1.0/me',
|
||||
['headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$token->getToken(),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'nickname' => null,
|
||||
'name' => $this->arrayItem($user, 'displayName'),
|
||||
'email' => $this->arrayItem($user, 'userPrincipalName'),
|
||||
'avatar' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return array_merge(parent::getTokenFields($code), [
|
||||
'grant_type' => 'authorization_code',
|
||||
]);
|
||||
}
|
||||
}
|
||||
206
vendor/overtrue/socialite/src/Providers/QQProvider.php
vendored
Normal file
206
vendor/overtrue/socialite/src/Providers/QQProvider.php
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class QQProvider.
|
||||
*
|
||||
* @see http://wiki.connect.qq.com/oauth2-0%E7%AE%80%E4%BB%8B [QQ - OAuth 2.0 登录QQ]
|
||||
*/
|
||||
class QQProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base url of QQ API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://graph.qq.com';
|
||||
|
||||
/**
|
||||
* User openid.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $openId;
|
||||
|
||||
/**
|
||||
* get token(openid) with unionid.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $withUnionId = false;
|
||||
|
||||
/**
|
||||
* User unionid.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $unionId;
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['get_user_info'];
|
||||
|
||||
/**
|
||||
* The uid of user authorized.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $uid;
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth2.0/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token URL for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/oauth2.0/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Post fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->getTokenUrl(), [
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token from the token response body.
|
||||
*
|
||||
* @param string $body
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function parseAccessToken($body)
|
||||
{
|
||||
parse_str($body, $token);
|
||||
|
||||
return parent::parseAccessToken($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public function withUnionId()
|
||||
{
|
||||
$this->withUnionId = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw user for the given access token.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$url = $this->baseUrl.'/oauth2.0/me?access_token='.$token->getToken();
|
||||
$this->withUnionId && $url .= '&unionid=1';
|
||||
|
||||
$response = $this->getHttpClient()->get($url);
|
||||
|
||||
$me = json_decode($this->removeCallback($response->getBody()->getContents()), true);
|
||||
$this->openId = $me['openid'];
|
||||
$this->unionId = isset($me['unionid']) ? $me['unionid'] : '';
|
||||
|
||||
$queries = [
|
||||
'access_token' => $token->getToken(),
|
||||
'openid' => $this->openId,
|
||||
'oauth_consumer_key' => $this->getConfig()->get('client_id'),
|
||||
];
|
||||
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/user/get_user_info?'.http_build_query($queries));
|
||||
|
||||
return json_decode($this->removeCallback($response->getBody()->getContents()), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the raw user array to a Socialite User instance.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->openId,
|
||||
'unionid' => $this->unionId,
|
||||
'nickname' => $this->arrayItem($user, 'nickname'),
|
||||
'name' => $this->arrayItem($user, 'nickname'),
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
'avatar' => $this->arrayItem($user, 'figureurl_qq_2'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the fucking callback parentheses.
|
||||
*
|
||||
* @param string $response
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function removeCallback($response)
|
||||
{
|
||||
if (false !== strpos($response, 'callback')) {
|
||||
$lpos = strpos($response, '(');
|
||||
$rpos = strrpos($response, ')');
|
||||
$response = substr($response, $lpos + 1, $rpos - $lpos - 1);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
242
vendor/overtrue/socialite/src/Providers/TaobaoProvider.php
vendored
Normal file
242
vendor/overtrue/socialite/src/Providers/TaobaoProvider.php
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class TaobaoProvider.
|
||||
*
|
||||
* @author mechono <haodouliu@gmail.com>
|
||||
*
|
||||
* @see https://open.taobao.com/doc.htm?docId=102635&docType=1&source=search [Taobao - OAuth 2.0 授权登录]
|
||||
*/
|
||||
class TaobaoProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base url of Taobao API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://oauth.taobao.com';
|
||||
|
||||
/**
|
||||
* Taobao API service URL address.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $gatewayUrl = 'https://eco.taobao.com/router/rest';
|
||||
|
||||
/**
|
||||
* The API version for the request.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version = '2.0';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $format = 'json';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signMethod = 'md5';
|
||||
|
||||
/**
|
||||
* Web 对应 PC 端(淘宝 logo )浏览器页面样式;Tmall 对应天猫的浏览器页面样式;Wap 对应无线端的浏览器页面样式。
|
||||
*/
|
||||
protected $view = 'web';
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['user_info'];
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权码接口参数.
|
||||
*
|
||||
* @param string|null $state
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCodeFields($state = null)
|
||||
{
|
||||
$fields = [
|
||||
'client_id' => $this->getConfig()->get('client_id'),
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'view' => $this->view,
|
||||
'response_type' => 'code',
|
||||
];
|
||||
|
||||
if ($this->usesState()) {
|
||||
$fields['state'] = $state;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token URL for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Post fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code', 'view' => $this->view];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token for the given code.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody()->getContents());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the access token from the token response body.
|
||||
*
|
||||
* @param string $body
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function parseAccessToken($body)
|
||||
{
|
||||
return parent::parseAccessToken($body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw user for the given access token.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getUserInfoUrl($this->gatewayUrl, $token));
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the raw user array to a Socialite User instance.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'open_id'),
|
||||
'nickname' => $this->arrayItem($user, 'nick'),
|
||||
'name' => $this->arrayItem($user, 'nick'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $params
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function generateSign($params)
|
||||
{
|
||||
ksort($params);
|
||||
|
||||
$stringToBeSigned = $this->getConfig()->get('client_secret');
|
||||
|
||||
foreach ($params as $k => $v) {
|
||||
if (!is_array($v) && '@' != substr($v, 0, 1)) {
|
||||
$stringToBeSigned .= "$k$v";
|
||||
}
|
||||
}
|
||||
|
||||
$stringToBeSigned .= $this->getConfig()->get('client_secret');
|
||||
|
||||
return strtoupper(md5($stringToBeSigned));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
* @param array $apiFields
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getPublicFields(AccessTokenInterface $token, array $apiFields = [])
|
||||
{
|
||||
$fields = [
|
||||
'app_key' => $this->getConfig()->get('client_id'),
|
||||
'sign_method' => $this->signMethod,
|
||||
'session' => $token->getToken(),
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'v' => $this->version,
|
||||
'format' => $this->format,
|
||||
];
|
||||
|
||||
$fields = array_merge($apiFields, $fields);
|
||||
$fields['sign'] = $this->generateSign($fields);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getUserInfoUrl($url, AccessTokenInterface $token)
|
||||
{
|
||||
$apiFields = ['method' => 'taobao.miniapp.userInfo.get'];
|
||||
|
||||
$query = http_build_query($this->getPublicFields($token, $apiFields), '', '&', $this->encodingType);
|
||||
|
||||
return $url.'?'.$query;
|
||||
}
|
||||
}
|
||||
234
vendor/overtrue/socialite/src/Providers/WeChatProvider.php
vendored
Normal file
234
vendor/overtrue/socialite/src/Providers/WeChatProvider.php
vendored
Normal file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\InvalidArgumentException;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
use Overtrue\Socialite\WeChatComponentInterface;
|
||||
|
||||
/**
|
||||
* Class WeChatProvider.
|
||||
*
|
||||
* @see http://mp.weixin.qq.com/wiki/9/01f711493b5a02f24b04365ac5d8fd95.html [WeChat - 公众平台OAuth文档]
|
||||
* @see https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN [网站应用微信登录开发指南]
|
||||
*/
|
||||
class WeChatProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base url of WeChat API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://api.weixin.qq.com/sns';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected $openId;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected $scopes = ['snsapi_login'];
|
||||
|
||||
/**
|
||||
* Indicates if the session state should be utilized.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $stateless = true;
|
||||
|
||||
/**
|
||||
* Return country code instead of country name.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $withCountryCode = false;
|
||||
|
||||
/**
|
||||
* @var WeChatComponentInterface
|
||||
*/
|
||||
protected $component;
|
||||
|
||||
/**
|
||||
* Return country code instead of country name.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function withCountryCode()
|
||||
{
|
||||
$this->withCountryCode = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* WeChat OpenPlatform 3rd component.
|
||||
*
|
||||
* @param WeChatComponentInterface $component
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function component(WeChatComponentInterface $component)
|
||||
{
|
||||
$this->scopes = ['snsapi_base'];
|
||||
|
||||
$this->component = $component;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
public function getAccessToken($code)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->getTokenUrl(), [
|
||||
'headers' => ['Accept' => 'application/json'],
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->parseAccessToken($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
$path = 'oauth2/authorize';
|
||||
|
||||
if (in_array('snsapi_login', $this->scopes)) {
|
||||
$path = 'qrconnect';
|
||||
}
|
||||
|
||||
return $this->buildAuthUrlFromBase("https://open.weixin.qq.com/connect/{$path}", $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function buildAuthUrlFromBase($url, $state)
|
||||
{
|
||||
$query = http_build_query($this->getCodeFields($state), '', '&', $this->encodingType);
|
||||
|
||||
return $url.'?'.$query.'#wechat_redirect';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getCodeFields($state = null)
|
||||
{
|
||||
if ($this->component) {
|
||||
$this->with(array_merge($this->parameters, ['component_appid' => $this->component->getAppId()]));
|
||||
}
|
||||
|
||||
return array_merge([
|
||||
'appid' => $this->getConfig()->get('client_id'),
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'response_type' => 'code',
|
||||
'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
'state' => $state ?: md5(time()),
|
||||
'connect_redirect' => 1,
|
||||
], $this->parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
if ($this->component) {
|
||||
return $this->baseUrl.'/oauth2/component/access_token';
|
||||
}
|
||||
|
||||
return $this->baseUrl.'/oauth2/access_token';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$scopes = explode(',', $token->getAttribute('scope', ''));
|
||||
|
||||
if (in_array('snsapi_base', $scopes)) {
|
||||
return $token->toArray();
|
||||
}
|
||||
|
||||
if (empty($token['openid'])) {
|
||||
throw new InvalidArgumentException('openid of AccessToken is required.');
|
||||
}
|
||||
|
||||
$language = $this->withCountryCode ? null : (isset($this->parameters['lang']) ? $this->parameters['lang'] : 'zh_CN');
|
||||
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/userinfo', [
|
||||
'query' => array_filter([
|
||||
'access_token' => $token->getToken(),
|
||||
'openid' => $token['openid'],
|
||||
'lang' => $language,
|
||||
]),
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'openid'),
|
||||
'name' => $this->arrayItem($user, 'nickname'),
|
||||
'nickname' => $this->arrayItem($user, 'nickname'),
|
||||
'avatar' => $this->arrayItem($user, 'headimgurl'),
|
||||
'email' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}.
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return array_filter([
|
||||
'appid' => $this->getConfig()->get('client_id'),
|
||||
'secret' => $this->getConfig()->get('client_secret'),
|
||||
'component_appid' => $this->component ? $this->component->getAppId() : null,
|
||||
'component_access_token' => $this->component ? $this->component->getToken() : null,
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the fucking callback parentheses.
|
||||
*
|
||||
* @param mixed $response
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function removeCallback($response)
|
||||
{
|
||||
if (false !== strpos($response, 'callback')) {
|
||||
$lpos = strpos($response, '(');
|
||||
$rpos = strrpos($response, ')');
|
||||
$response = substr($response, $lpos + 1, $rpos - $lpos - 1);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
214
vendor/overtrue/socialite/src/Providers/WeWorkProvider.php
vendored
Normal file
214
vendor/overtrue/socialite/src/Providers/WeWorkProvider.php
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class WeWorkProvider.
|
||||
*
|
||||
* @author mingyoung <mingyoungcheung@gmail.com>
|
||||
*/
|
||||
class WeWorkProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $agentId;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $detailed = false;
|
||||
|
||||
/**
|
||||
* Set agent id.
|
||||
*
|
||||
* @param string $agentId
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAgentId($agentId)
|
||||
{
|
||||
$this->agentId = $agentId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $agentId
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function agent($agentId)
|
||||
{
|
||||
return $this->setAgentId($agentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return user details.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function detailed()
|
||||
{
|
||||
$this->detailed = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
// 网页授权登录
|
||||
if (!empty($this->scopes)) {
|
||||
return $this->getOAuthUrl($state);
|
||||
}
|
||||
|
||||
// 第三方网页应用登录(扫码登录)
|
||||
return $this->getQrConnectUrl($state);
|
||||
}
|
||||
|
||||
/**
|
||||
* OAuth url.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getOAuthUrl($state)
|
||||
{
|
||||
$queries = [
|
||||
'appid' => $this->getConfig()->get('client_id'),
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'response_type' => 'code',
|
||||
'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
'agentid' => $this->agentId,
|
||||
'state' => $state,
|
||||
];
|
||||
|
||||
return sprintf('https://open.weixin.qq.com/connect/oauth2/authorize?%s#wechat_redirect', http_build_query($queries));
|
||||
}
|
||||
|
||||
/**
|
||||
* Qr connect url.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getQrConnectUrl($state)
|
||||
{
|
||||
$queries = [
|
||||
'appid' => $this->getConfig()->get('client_id'),
|
||||
'agentid' => $this->agentId,
|
||||
'redirect_uri' => $this->redirectUrl,
|
||||
'state' => $state,
|
||||
];
|
||||
|
||||
return 'https://open.work.weixin.qq.com/wwopen/sso/qrConnect?'.http_build_query($queries);
|
||||
}
|
||||
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$userInfo = $this->getUserInfo($token);
|
||||
|
||||
if ($this->detailed && isset($userInfo['user_ticket'])) {
|
||||
return $this->getUserDetail($token, $userInfo['user_ticket']);
|
||||
}
|
||||
|
||||
$this->detailed = false;
|
||||
|
||||
return $userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user base info.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getUserInfo(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get('https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo', [
|
||||
'query' => array_filter([
|
||||
'access_token' => $token->getToken(),
|
||||
'code' => $this->getCode(),
|
||||
]),
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user detail info.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
* @param $ticket
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getUserDetail(AccessTokenInterface $token, $ticket)
|
||||
{
|
||||
$response = $this->getHttpClient()->post('https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail', [
|
||||
'query' => [
|
||||
'access_token' => $token->getToken(),
|
||||
],
|
||||
'json' => [
|
||||
'user_ticket' => $ticket,
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
if ($this->detailed) {
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'userid'),
|
||||
'name' => $this->arrayItem($user, 'name'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar'),
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
]);
|
||||
}
|
||||
|
||||
return new User(array_filter([
|
||||
'id' => $this->arrayItem($user, 'UserId') ?: $this->arrayItem($user, 'OpenId'),
|
||||
'userId' => $this->arrayItem($user, 'UserId'),
|
||||
'openid' => $this->arrayItem($user, 'OpenId'),
|
||||
'deviceId' => $this->arrayItem($user, 'DeviceId'),
|
||||
]));
|
||||
}
|
||||
}
|
||||
126
vendor/overtrue/socialite/src/Providers/WeiboProvider.php
vendored
Normal file
126
vendor/overtrue/socialite/src/Providers/WeiboProvider.php
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\ProviderInterface;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* Class WeiboProvider.
|
||||
*
|
||||
* @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 授权机制说明]
|
||||
*/
|
||||
class WeiboProvider extends AbstractProvider implements ProviderInterface
|
||||
{
|
||||
/**
|
||||
* The base url of Weibo API.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $baseUrl = 'https://api.weibo.com';
|
||||
|
||||
/**
|
||||
* The API version for the request.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version = '2';
|
||||
|
||||
/**
|
||||
* The scopes being requested.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $scopes = ['email'];
|
||||
|
||||
/**
|
||||
* The uid of user authorized.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $uid;
|
||||
|
||||
/**
|
||||
* Get the authentication URL for the provider.
|
||||
*
|
||||
* @param string $state
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth2/authorize', $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the token URL for the provider.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return $this->baseUrl.'/'.$this->version.'/oauth2/access_token';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Post fields for the token request.
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getTokenFields($code)
|
||||
{
|
||||
return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the raw user for the given access token.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/'.$this->version.'/users/show.json', [
|
||||
'query' => [
|
||||
'uid' => $token['uid'],
|
||||
'access_token' => $token->getToken(),
|
||||
],
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
return json_decode($response->getBody(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the raw user array to a Socialite User instance.
|
||||
*
|
||||
* @param array $user
|
||||
*
|
||||
* @return \Overtrue\Socialite\User
|
||||
*/
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User([
|
||||
'id' => $this->arrayItem($user, 'id'),
|
||||
'nickname' => $this->arrayItem($user, 'screen_name'),
|
||||
'name' => $this->arrayItem($user, 'name'),
|
||||
'email' => $this->arrayItem($user, 'email'),
|
||||
'avatar' => $this->arrayItem($user, 'avatar_large'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
251
vendor/overtrue/socialite/src/SocialiteManager.php
vendored
Normal file
251
vendor/overtrue/socialite/src/SocialiteManager.php
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
use Closure;
|
||||
use InvalidArgumentException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Session\Session;
|
||||
|
||||
/**
|
||||
* Class SocialiteManager.
|
||||
*/
|
||||
class SocialiteManager implements FactoryInterface
|
||||
{
|
||||
/**
|
||||
* The configuration.
|
||||
*
|
||||
* @var \Overtrue\Socialite\Config
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* The request instance.
|
||||
*
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* The registered custom driver creators.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $customCreators = [];
|
||||
|
||||
/**
|
||||
* The initial drivers.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $initialDrivers = [
|
||||
'facebook' => 'Facebook',
|
||||
'github' => 'GitHub',
|
||||
'google' => 'Google',
|
||||
'linkedin' => 'Linkedin',
|
||||
'weibo' => 'Weibo',
|
||||
'qq' => 'QQ',
|
||||
'wechat' => 'WeChat',
|
||||
'douban' => 'Douban',
|
||||
'wework' => 'WeWork',
|
||||
'outlook' => 'Outlook',
|
||||
'douyin' => 'DouYin',
|
||||
'taobao' => 'Taobao',
|
||||
'feishu' => 'FeiShu',
|
||||
];
|
||||
|
||||
/**
|
||||
* The array of created "drivers".
|
||||
*
|
||||
* @var ProviderInterface[]
|
||||
*/
|
||||
protected $drivers = [];
|
||||
|
||||
/**
|
||||
* SocialiteManager constructor.
|
||||
*
|
||||
* @param array $config
|
||||
* @param Request|null $request
|
||||
*/
|
||||
public function __construct(array $config, Request $request = null)
|
||||
{
|
||||
$this->config = new Config($config);
|
||||
|
||||
if ($this->config->has('guzzle')) {
|
||||
Providers\AbstractProvider::setGuzzleOptions($this->config->get('guzzle'));
|
||||
}
|
||||
|
||||
if ($request) {
|
||||
$this->setRequest($request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set config instance.
|
||||
*
|
||||
* @param \Overtrue\Socialite\Config $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function config(Config $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a driver instance.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
public function driver($driver)
|
||||
{
|
||||
$driver = strtolower($driver);
|
||||
|
||||
if (!isset($this->drivers[$driver])) {
|
||||
$this->drivers[$driver] = $this->createDriver($driver);
|
||||
}
|
||||
|
||||
return $this->drivers[$driver];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequest(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request ?: $this->createDefaultRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new driver instance.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
protected function createDriver($driver)
|
||||
{
|
||||
if (isset($this->customCreators[$driver])) {
|
||||
return $this->callCustomCreator($driver);
|
||||
}
|
||||
|
||||
if (isset($this->initialDrivers[$driver])) {
|
||||
$provider = $this->initialDrivers[$driver];
|
||||
$provider = __NAMESPACE__.'\\Providers\\'.$provider.'Provider';
|
||||
|
||||
return $this->buildProvider($provider, $this->formatConfig($this->config->get($driver)));
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("Driver [$driver] not supported.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a custom driver creator.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
protected function callCustomCreator($driver)
|
||||
{
|
||||
return $this->customCreators[$driver]($this->config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create default request instance.
|
||||
*
|
||||
* @return Request
|
||||
*/
|
||||
protected function createDefaultRequest()
|
||||
{
|
||||
$request = Request::createFromGlobals();
|
||||
$session = new Session();
|
||||
|
||||
$request->setSession($session);
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom driver creator Closure.
|
||||
*
|
||||
* @param string $driver
|
||||
* @param \Closure $callback
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function extend($driver, Closure $callback)
|
||||
{
|
||||
$driver = strtolower($driver);
|
||||
|
||||
$this->customCreators[$driver] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the created "drivers".
|
||||
*
|
||||
* @return ProviderInterface[]
|
||||
*/
|
||||
public function getDrivers()
|
||||
{
|
||||
return $this->drivers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an OAuth 2 provider instance.
|
||||
*
|
||||
* @param string $provider
|
||||
* @param array $config
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
public function buildProvider($provider, $config)
|
||||
{
|
||||
return new $provider($this->getRequest(), $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the server configuration.
|
||||
*
|
||||
* @param array $config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function formatConfig(array $config)
|
||||
{
|
||||
return array_merge([
|
||||
'identifier' => $config['client_id'],
|
||||
'secret' => $config['client_secret'],
|
||||
'callback_uri' => $config['redirect'],
|
||||
], $config);
|
||||
}
|
||||
}
|
||||
204
vendor/overtrue/socialite/src/User.php
vendored
Normal file
204
vendor/overtrue/socialite/src/User.php
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
use ArrayAccess;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* Class User.
|
||||
*/
|
||||
class User implements ArrayAccess, UserInterface, JsonSerializable, \Serializable
|
||||
{
|
||||
use HasAttributes;
|
||||
|
||||
/**
|
||||
* User constructor.
|
||||
*
|
||||
* @param array $attributes
|
||||
*/
|
||||
public function __construct(array $attributes)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unique identifier for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->getAttribute('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the username for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->getAttribute('username', $this->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the nickname / username for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNickname()
|
||||
{
|
||||
return $this->getAttribute('nickname');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full name of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->getAttribute('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the e-mail address of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmail()
|
||||
{
|
||||
return $this->getAttribute('email');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the avatar / image URL for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAvatar()
|
||||
{
|
||||
return $this->getAttribute('avatar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the token on the user.
|
||||
*
|
||||
* @param \Overtrue\Socialite\AccessTokenInterface $token
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setToken(AccessTokenInterface $token)
|
||||
{
|
||||
$this->setAttribute('token', $token->getToken());
|
||||
$this->setAttribute('access_token', $token->getToken());
|
||||
|
||||
if (\is_callable([$token, 'getRefreshToken'])) {
|
||||
$this->setAttribute('refresh_token', $token->getRefreshToken());
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $provider
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProviderName($provider)
|
||||
{
|
||||
$this->setAttribute('provider', $provider);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getProviderName()
|
||||
{
|
||||
return $this->getAttribute('provider');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authorized token.
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getToken()
|
||||
{
|
||||
return new AccessToken([
|
||||
'access_token' => $this->getAccessToken(),
|
||||
'refresh_token' => $this->getAttribute('refresh_token')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user access token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken()
|
||||
{
|
||||
return $this->getAttribute('token') ?: $this->getAttribute('access_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user refresh token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRefreshToken()
|
||||
{
|
||||
return $this->getAttribute('refresh_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original attributes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOriginal()
|
||||
{
|
||||
return $this->getAttribute('original');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
return serialize($this->attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the object.
|
||||
*
|
||||
* @see https://php.net/manual/en/serializable.unserialize.php
|
||||
*
|
||||
* @param string $serialized <p>
|
||||
* The string representation of the object.
|
||||
* </p>
|
||||
*
|
||||
* @since 5.1.0
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
$this->attributes = unserialize($serialized) ?: [];
|
||||
}
|
||||
}
|
||||
53
vendor/overtrue/socialite/src/UserInterface.php
vendored
Normal file
53
vendor/overtrue/socialite/src/UserInterface.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
/**
|
||||
* Interface UserInterface.
|
||||
*/
|
||||
interface UserInterface
|
||||
{
|
||||
/**
|
||||
* Get the unique identifier for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId();
|
||||
|
||||
/**
|
||||
* Get the nickname / username for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNickname();
|
||||
|
||||
/**
|
||||
* Get the full name of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Get the e-mail address of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmail();
|
||||
|
||||
/**
|
||||
* Get the avatar / image URL for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAvatar();
|
||||
}
|
||||
32
vendor/overtrue/socialite/src/WeChatComponentInterface.php
vendored
Normal file
32
vendor/overtrue/socialite/src/WeChatComponentInterface.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Overtrue\Socialite;
|
||||
|
||||
/**
|
||||
* Interface WeChatComponentInterface.
|
||||
*/
|
||||
interface WeChatComponentInterface
|
||||
{
|
||||
/**
|
||||
* Return the open-platform component app id.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAppId();
|
||||
|
||||
/**
|
||||
* Return the open-platform component access token string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getToken();
|
||||
}
|
||||
243
vendor/overtrue/socialite/tests/OAuthTest.php
vendored
Normal file
243
vendor/overtrue/socialite/tests/OAuthTest.php
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
use Mockery as m;
|
||||
use Overtrue\Socialite\AccessTokenInterface;
|
||||
use Overtrue\Socialite\Providers\AbstractProvider;
|
||||
use Overtrue\Socialite\User;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class OAuthTest extends TestCase
|
||||
{
|
||||
public function tearDown()
|
||||
{
|
||||
m::close();
|
||||
}
|
||||
|
||||
public function testAbstractProviderBackwardCompatible()
|
||||
{
|
||||
$request = Request::create('foo');
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
$session->shouldReceive('put')->once();
|
||||
$provider = new OAuthTwoTestProviderStub($request, 'client_id', 'client_secret', 'redirect');
|
||||
|
||||
$this->assertSame('client_id', $provider->getConfig()['client_id']);
|
||||
$this->assertSame('client_secret', $provider->getConfig()['client_secret']);
|
||||
$this->assertSame('redirect', $provider->getConfig()['redirect']);
|
||||
|
||||
$response = $provider->redirect();
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response);
|
||||
$this->assertSame('http://auth.url', $response->getTargetUrl());
|
||||
}
|
||||
|
||||
public function testRedirectGeneratesTheProperSymfonyRedirectResponse()
|
||||
{
|
||||
$request = Request::create('foo');
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
$session->shouldReceive('put')->once();
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect',
|
||||
]
|
||||
);
|
||||
$response = $provider->redirect();
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response);
|
||||
$this->assertSame('http://auth.url', $response->getTargetUrl());
|
||||
}
|
||||
|
||||
public function testRedirectUrl()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => str_repeat('A', 40), 'code' => 'code']);
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
]
|
||||
);
|
||||
$this->assertNull($provider->getRedirectUrl());
|
||||
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect_uri',
|
||||
]
|
||||
);
|
||||
$this->assertSame('redirect_uri', $provider->getRedirectUrl());
|
||||
$provider->setRedirectUrl('overtrue.me');
|
||||
$this->assertSame('overtrue.me', $provider->getRedirectUrl());
|
||||
|
||||
$provider->withRedirectUrl('http://overtrue.me');
|
||||
$this->assertSame('http://overtrue.me', $provider->getRedirectUrl());
|
||||
}
|
||||
|
||||
public function testUserReturnsAUserInstanceForTheAuthenticatedRequest()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => str_repeat('A', 40), 'code' => 'code']);
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
|
||||
$session->shouldReceive('get')->once()->with('state')->andReturn(str_repeat('A', 40));
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect_uri',
|
||||
]
|
||||
);
|
||||
$provider->http = m::mock('StdClass');
|
||||
$provider->http->shouldReceive('post')->once()->with(
|
||||
'http://token.url',
|
||||
[
|
||||
'headers' => ['Accept' => 'application/json'],
|
||||
'form_params' => [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'code' => 'code',
|
||||
'redirect_uri' => 'redirect_uri',
|
||||
],
|
||||
]
|
||||
)->andReturn($response = m::mock('StdClass'));
|
||||
$response->shouldReceive('getBody')->once()->andReturn('{"access_token":"access_token"}');
|
||||
$user = $provider->user();
|
||||
|
||||
$this->assertInstanceOf('Overtrue\Socialite\User', $user);
|
||||
$this->assertSame('foo', $user->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Overtrue\Socialite\InvalidStateException
|
||||
*/
|
||||
public function testExceptionIsThrownIfStateIsInvalid()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => str_repeat('B', 40), 'code' => 'code']);
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
$session->shouldReceive('get')->once()->with('state')->andReturn(str_repeat('A', 40));
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect',
|
||||
]
|
||||
);
|
||||
$user = $provider->user();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Overtrue\Socialite\AuthorizeFailedException
|
||||
* @expectedExceptionMessage Authorize Failed: {"error":"scope is invalid"}
|
||||
*/
|
||||
public function testExceptionisThrownIfAuthorizeFailed()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => str_repeat('A', 40), 'code' => 'code']);
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
$session->shouldReceive('get')->once()->with('state')->andReturn(str_repeat('A', 40));
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect_uri',
|
||||
]
|
||||
);
|
||||
$provider->http = m::mock('StdClass');
|
||||
$provider->http->shouldReceive('post')->once()->with(
|
||||
'http://token.url',
|
||||
[
|
||||
'headers' => ['Accept' => 'application/json'],
|
||||
'form_params' => [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'code' => 'code',
|
||||
'redirect_uri' => 'redirect_uri',
|
||||
],
|
||||
]
|
||||
)->andReturn($response = m::mock('StdClass'));
|
||||
$response->shouldReceive('getBody')->once()->andReturn('{"error":"scope is invalid"}');
|
||||
$user = $provider->user();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Overtrue\Socialite\InvalidStateException
|
||||
*/
|
||||
public function testExceptionIsThrownIfStateIsNotSet()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => 'state', 'code' => 'code']);
|
||||
$request->setSession($session = m::mock('Symfony\Component\HttpFoundation\Session\SessionInterface'));
|
||||
$session->shouldReceive('get')->once()->with('state');
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect',
|
||||
]
|
||||
);
|
||||
$user = $provider->user();
|
||||
}
|
||||
|
||||
public function testDriverName()
|
||||
{
|
||||
$request = Request::create('foo', 'GET', ['state' => 'state', 'code' => 'code']);
|
||||
$provider = new OAuthTwoTestProviderStub(
|
||||
$request, [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'redirect',
|
||||
]
|
||||
);
|
||||
|
||||
$this->assertSame('OAuthTwoTest', $provider->getName());
|
||||
}
|
||||
}
|
||||
|
||||
class OAuthTwoTestProviderStub extends AbstractProvider
|
||||
{
|
||||
public $http;
|
||||
|
||||
protected function getAuthUrl($state)
|
||||
{
|
||||
return 'http://auth.url';
|
||||
}
|
||||
|
||||
protected function getTokenUrl()
|
||||
{
|
||||
return 'http://token.url';
|
||||
}
|
||||
|
||||
protected function getUserByToken(AccessTokenInterface $token)
|
||||
{
|
||||
return ['id' => 'foo'];
|
||||
}
|
||||
|
||||
protected function mapUserToObject(array $user)
|
||||
{
|
||||
return new User(['id' => $user['id']]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a fresh instance of the Guzzle HTTP client.
|
||||
*
|
||||
* @return \GuzzleHttp\Client
|
||||
*/
|
||||
protected function getHttpClient()
|
||||
{
|
||||
if ($this->http) {
|
||||
return $this->http;
|
||||
}
|
||||
|
||||
return $this->http = m::mock('StdClass');
|
||||
}
|
||||
}
|
||||
60
vendor/overtrue/socialite/tests/Providers/WeWorkProviderTest.php
vendored
Normal file
60
vendor/overtrue/socialite/tests/Providers/WeWorkProviderTest.php
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
use Overtrue\Socialite\Providers\WeWorkProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class WeWorkProviderTest extends TestCase
|
||||
{
|
||||
public function testQrConnect()
|
||||
{
|
||||
$response = (new WeWorkProvider(Request::create('foo'), [
|
||||
'client_id' => 'ww100000a5f2191',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'http://www.oa.com',
|
||||
]))
|
||||
->setAgentId('1000000')
|
||||
->stateless()
|
||||
->redirect();
|
||||
|
||||
$this->assertSame('https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=ww100000a5f2191&agentid=1000000&redirect_uri=http%3A%2F%2Fwww.oa.com', $response->getTargetUrl());
|
||||
}
|
||||
|
||||
public function testOAuthWithAgentId()
|
||||
{
|
||||
$response = (new WeWorkProvider(Request::create('foo'), [
|
||||
'client_id' => 'CORPID',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'REDIRECT_URI',
|
||||
]))
|
||||
->scopes(['snsapi_base'])
|
||||
->setAgentId('1000000')
|
||||
->stateless()
|
||||
->redirect();
|
||||
|
||||
$this->assertSame('https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base&agentid=1000000#wechat_redirect', $response->getTargetUrl());
|
||||
}
|
||||
|
||||
public function testOAuthWithoutAgentId()
|
||||
{
|
||||
$response = (new WeWorkProvider(Request::create('foo'), [
|
||||
'client_id' => 'CORPID',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'REDIRECT_URI',
|
||||
]))
|
||||
->scopes(['snsapi_base'])
|
||||
->stateless()
|
||||
->redirect();
|
||||
|
||||
$this->assertSame('https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_base#wechat_redirect', $response->getTargetUrl());
|
||||
}
|
||||
}
|
||||
45
vendor/overtrue/socialite/tests/UserTest.php
vendored
Normal file
45
vendor/overtrue/socialite/tests/UserTest.php
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
use Overtrue\Socialite\AccessToken;
|
||||
use Overtrue\Socialite\User;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class UserTest extends TestCase
|
||||
{
|
||||
public function testJsonserialize()
|
||||
{
|
||||
$this->assertSame('[]', json_encode(new User([])));
|
||||
|
||||
$this->assertSame('{"token":"mock-token"}', json_encode(new User(['token' => new AccessToken(['access_token' => 'mock-token'])])));
|
||||
}
|
||||
|
||||
public function test_it_can_get_refresh_token()
|
||||
{
|
||||
$user = new User([
|
||||
'access_token' => 'mock-token',
|
||||
'refresh_token' => 'fake_refresh',
|
||||
]);
|
||||
|
||||
// 能通过用 User 对象获取 refresh token
|
||||
$this->assertSame('fake_refresh', $user->getRefreshToken());
|
||||
// json 序列化只有 token 字段
|
||||
$this->assertSame('{"access_token":"mock-token","refresh_token":"fake_refresh"}', json_encode($user));
|
||||
|
||||
$user = new User([]);
|
||||
$user->setToken(new AccessToken([
|
||||
'access_token' => 'mock-token',
|
||||
'refresh_token' => 'fake_refresh',
|
||||
]));
|
||||
$this->assertSame('fake_refresh', $user->getRefreshToken());
|
||||
$this->assertSame('{"token":"mock-token","access_token":"mock-token","refresh_token":"fake_refresh"}', json_encode($user));
|
||||
}
|
||||
}
|
||||
137
vendor/overtrue/socialite/tests/WechatProviderTest.php
vendored
Normal file
137
vendor/overtrue/socialite/tests/WechatProviderTest.php
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the overtrue/socialite.
|
||||
*
|
||||
* (c) overtrue <i@overtrue.me>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
use Overtrue\Socialite\Providers\WeChatProvider as RealWeChatProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class WechatProviderTest extends TestCase
|
||||
{
|
||||
public function testWeChatProviderHasCorrectlyRedirectResponse()
|
||||
{
|
||||
$response = (new WeChatProvider(Request::create('foo'), [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'http://localhost/socialite/callback.php',
|
||||
]))->redirect();
|
||||
|
||||
$this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response);
|
||||
$this->assertStringStartsWith('https://open.weixin.qq.com/connect/qrconnect', $response->getTargetUrl());
|
||||
$this->assertRegExp('/redirect_uri=http%3A%2F%2Flocalhost%2Fsocialite%2Fcallback.php/', $response->getTargetUrl());
|
||||
}
|
||||
|
||||
public function testWeChatProviderTokenUrlAndRequestFields()
|
||||
{
|
||||
$provider = new WeChatProvider(Request::create('foo'), [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => 'client_secret',
|
||||
'redirect' => 'http://localhost/socialite/callback.php',
|
||||
]);
|
||||
|
||||
$this->assertSame('https://api.weixin.qq.com/sns/oauth2/access_token', $provider->tokenUrl());
|
||||
$this->assertSame([
|
||||
'appid' => 'client_id',
|
||||
'secret' => 'client_secret',
|
||||
'code' => 'iloveyou',
|
||||
'grant_type' => 'authorization_code',
|
||||
], $provider->tokenFields('iloveyou'));
|
||||
|
||||
$this->assertSame([
|
||||
'appid' => 'client_id',
|
||||
'redirect_uri' => 'http://localhost/socialite/callback.php',
|
||||
'response_type' => 'code',
|
||||
'scope' => 'snsapi_login',
|
||||
'state' => 'wechat-state',
|
||||
'connect_redirect' => 1,
|
||||
], $provider->codeFields('wechat-state'));
|
||||
}
|
||||
|
||||
public function testOpenPlatformComponent()
|
||||
{
|
||||
$provider = new WeChatProvider(Request::create('foo'), [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => null,
|
||||
'redirect' => 'redirect-url',
|
||||
]);
|
||||
$provider->component(new WeChatComponent());
|
||||
$this->assertSame([
|
||||
'appid' => 'client_id',
|
||||
'redirect_uri' => 'redirect-url',
|
||||
'response_type' => 'code',
|
||||
'scope' => 'snsapi_base',
|
||||
'state' => 'state',
|
||||
'connect_redirect' => 1,
|
||||
'component_appid' => 'component-app-id',
|
||||
], $provider->codeFields('state'));
|
||||
|
||||
$this->assertSame([
|
||||
'appid' => 'client_id',
|
||||
'component_appid' => 'component-app-id',
|
||||
'component_access_token' => 'token',
|
||||
'code' => 'simcode',
|
||||
'grant_type' => 'authorization_code',
|
||||
], $provider->tokenFields('simcode'));
|
||||
|
||||
$this->assertSame('https://api.weixin.qq.com/sns/oauth2/component/access_token', $provider->tokenUrl());
|
||||
}
|
||||
|
||||
public function testOpenPlatformComponentWithCustomParameters()
|
||||
{
|
||||
$provider = new WeChatProvider(Request::create('foo'), [
|
||||
'client_id' => 'client_id',
|
||||
'client_secret' => null,
|
||||
'redirect' => 'redirect-url',
|
||||
]);
|
||||
$provider->component(new WeChatComponent());
|
||||
$provider->with(['foo' => 'bar']);
|
||||
|
||||
$fields = $provider->codeFields('wechat-state');
|
||||
|
||||
$this->assertArrayHasKey('foo', $fields);
|
||||
$this->assertSame('bar', $fields['foo']);
|
||||
}
|
||||
}
|
||||
|
||||
trait ProviderTrait
|
||||
{
|
||||
public function tokenUrl()
|
||||
{
|
||||
return $this->getTokenUrl();
|
||||
}
|
||||
|
||||
public function tokenFields($code)
|
||||
{
|
||||
return $this->getTokenFields($code);
|
||||
}
|
||||
|
||||
public function codeFields($state = null)
|
||||
{
|
||||
return $this->getCodeFields($state);
|
||||
}
|
||||
}
|
||||
|
||||
class WeChatProvider extends RealWeChatProvider
|
||||
{
|
||||
use ProviderTrait;
|
||||
}
|
||||
|
||||
class WeChatComponent implements \Overtrue\Socialite\WeChatComponentInterface
|
||||
{
|
||||
public function getAppId()
|
||||
{
|
||||
return 'component-app-id';
|
||||
}
|
||||
|
||||
public function getToken()
|
||||
{
|
||||
return 'token';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user