fix:更新已知bug,优化代码
This commit is contained in:
84
vendor/overtrue/socialite/src/AccessToken.php
vendored
84
vendor/overtrue/socialite/src/AccessToken.php
vendored
@@ -1,84 +0,0 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?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();
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
158
vendor/overtrue/socialite/src/Config.php
vendored
158
vendor/overtrue/socialite/src/Config.php
vendored
@@ -1,59 +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;
|
||||
|
||||
use ArrayAccess;
|
||||
use InvalidArgumentException;
|
||||
use JsonSerializable;
|
||||
|
||||
/**
|
||||
* Class Config.
|
||||
*/
|
||||
class Config implements ArrayAccess
|
||||
class Config implements ArrayAccess, JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $config;
|
||||
protected array $config;
|
||||
|
||||
/**
|
||||
* Config constructor.
|
||||
*
|
||||
* @param array $config
|
||||
* @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)
|
||||
public function get(string $key, mixed $default = null): mixed
|
||||
{
|
||||
$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)) {
|
||||
|
||||
foreach (\explode('.', $key) as $segment) {
|
||||
if (! \is_array($config) || ! \array_key_exists($segment, $config)) {
|
||||
return $default;
|
||||
}
|
||||
$config = $config[$segment];
|
||||
@@ -62,119 +35,64 @@ class Config implements ArrayAccess
|
||||
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)
|
||||
public function set(string $key, mixed $value): array
|
||||
{
|
||||
if (is_null($key)) {
|
||||
throw new InvalidArgumentException('Invalid config key.');
|
||||
}
|
||||
|
||||
$keys = explode('.', $key);
|
||||
$keys = \explode('.', $key);
|
||||
$config = &$this->config;
|
||||
|
||||
while (count($keys) > 1) {
|
||||
$key = array_shift($keys);
|
||||
if (!isset($config[$key]) || !is_array($config[$key])) {
|
||||
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;
|
||||
$config[\array_shift($keys)] = $value;
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given configuration value exists.
|
||||
*
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has($key)
|
||||
public function has(string $key): bool
|
||||
{
|
||||
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)
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
return array_key_exists($offset, $this->config);
|
||||
\is_string($offset) || throw new Exceptions\InvalidArgumentException('The $offset must be type of string here.');
|
||||
|
||||
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)
|
||||
public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
\is_string($offset) || throw new Exceptions\InvalidArgumentException('The $offset must be type of string here.');
|
||||
|
||||
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)
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
\is_string($offset) || throw new Exceptions\InvalidArgumentException('The $offset must be type of string here.');
|
||||
|
||||
$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)
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
\is_string($offset) || throw new Exceptions\InvalidArgumentException('The $offset must be type of string here.');
|
||||
|
||||
$this->set($offset, null);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return \json_encode($this, \JSON_UNESCAPED_UNICODE) ?: '';
|
||||
}
|
||||
}
|
||||
|
||||
19
vendor/overtrue/socialite/src/Contracts/FactoryInterface.php
vendored
Normal file
19
vendor/overtrue/socialite/src/Contracts/FactoryInterface.php
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Contracts;
|
||||
|
||||
const ABNF_APP_ID = 'app_id';
|
||||
const ABNF_APP_SECRET = 'app_secret';
|
||||
const ABNF_OPEN_ID = 'open_id';
|
||||
const ABNF_TOKEN = 'token';
|
||||
|
||||
interface FactoryInterface
|
||||
{
|
||||
public function config(\Overtrue\Socialite\Config $config): self;
|
||||
|
||||
public function create(string $name): ProviderInterface;
|
||||
|
||||
public function getResolvedProviders(): array;
|
||||
|
||||
public function buildProvider(string $provider, array $config): ProviderInterface;
|
||||
}
|
||||
68
vendor/overtrue/socialite/src/Contracts/ProviderInterface.php
vendored
Normal file
68
vendor/overtrue/socialite/src/Contracts/ProviderInterface.php
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Contracts;
|
||||
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.1 */
|
||||
const RFC6749_ABNF_CLIENT_ID = 'client_id';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.2 */
|
||||
const RFC6749_ABNF_CLIENT_SECRET = 'client_secret';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.3 */
|
||||
const RFC6749_ABNF_RESPONSE_TYPE = 'response_type';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.4 */
|
||||
const RFC6749_ABNF_SCOPE = 'scope';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.5 */
|
||||
const RFC6749_ABNF_STATE = 'state';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.6 */
|
||||
const RFC6749_ABNF_REDIRECT_URI = 'redirect_uri';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.7 */
|
||||
const RFC6749_ABNF_ERROR = 'error';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.8 */
|
||||
const RFC6749_ABNF_ERROR_DESCRIPTION = 'error_description';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.9 */
|
||||
const RFC6749_ABNF_ERROR_URI = 'error_uri';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.10 */
|
||||
const RFC6749_ABNF_GRANT_TYPE = 'grant_type';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.11 */
|
||||
const RFC6749_ABNF_CODE = 'code';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.12 */
|
||||
const RFC6749_ABNF_ACCESS_TOKEN = 'access_token';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.13 */
|
||||
const RFC6749_ABNF_TOKEN_TYPE = 'token_type';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.14 */
|
||||
const RFC6749_ABNF_EXPIRES_IN = 'expires_in';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.15 */
|
||||
const RFC6749_ABNF_USERNAME = 'username';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.16 */
|
||||
const RFC6749_ABNF_PASSWORD = 'password';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#appendix-A.17 */
|
||||
const RFC6749_ABNF_REFRESH_TOKEN = 'refresh_token';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3 */
|
||||
const RFC6749_ABNF_AUTHORATION_CODE = 'authorization_code';
|
||||
/** @see https://datatracker.ietf.org/doc/html/rfc6749#section-4.4.2 */
|
||||
const RFC6749_ABNF_CLIENT_CREDENTIALS = 'client_credentials';
|
||||
|
||||
interface ProviderInterface
|
||||
{
|
||||
public function redirect(?string $redirectUrl = null): string;
|
||||
|
||||
public function userFromCode(string $code): UserInterface;
|
||||
|
||||
public function userFromToken(string $token): UserInterface;
|
||||
|
||||
public function withRedirectUrl(string $redirectUrl): self;
|
||||
|
||||
public function withState(string $state): self;
|
||||
|
||||
/**
|
||||
* @param string[] $scopes
|
||||
*/
|
||||
public function scopes(array $scopes): self;
|
||||
|
||||
public function with(array $parameters): self;
|
||||
|
||||
public function withScopeSeparator(string $scopeSeparator): self;
|
||||
|
||||
public function getClientId(): ?string;
|
||||
|
||||
public function getClientSecret(): ?string;
|
||||
}
|
||||
46
vendor/overtrue/socialite/src/Contracts/UserInterface.php
vendored
Normal file
46
vendor/overtrue/socialite/src/Contracts/UserInterface.php
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Contracts;
|
||||
|
||||
const ABNF_ID = 'id';
|
||||
const ABNF_NAME = 'name';
|
||||
const ABNF_NICKNAME = 'nickname';
|
||||
const ABNF_EMAIL = 'email';
|
||||
const ABNF_AVATAR = 'avatar';
|
||||
|
||||
interface UserInterface
|
||||
{
|
||||
public function getId(): mixed;
|
||||
|
||||
public function getNickname(): ?string;
|
||||
|
||||
public function getName(): ?string;
|
||||
|
||||
public function getEmail(): ?string;
|
||||
|
||||
public function getAvatar(): ?string;
|
||||
|
||||
public function getAccessToken(): ?string;
|
||||
|
||||
public function getRefreshToken(): ?string;
|
||||
|
||||
public function getExpiresIn(): ?int;
|
||||
|
||||
public function getProvider(): ProviderInterface;
|
||||
|
||||
public function setRefreshToken(?string $refreshToken): self;
|
||||
|
||||
public function setExpiresIn(int $expiresIn): self;
|
||||
|
||||
public function setTokenResponse(array $response): self;
|
||||
|
||||
public function getTokenResponse(): mixed;
|
||||
|
||||
public function setProvider(ProviderInterface $provider): self;
|
||||
|
||||
public function getRaw(): array;
|
||||
|
||||
public function setRaw(array $user): self;
|
||||
|
||||
public function setAccessToken(string $token): self;
|
||||
}
|
||||
18
vendor/overtrue/socialite/src/Exceptions/AuthorizeFailedException.php
vendored
Normal file
18
vendor/overtrue/socialite/src/Exceptions/AuthorizeFailedException.php
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Exceptions;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
|
||||
class AuthorizeFailedException extends Exception
|
||||
{
|
||||
public array $body;
|
||||
|
||||
#[Pure]
|
||||
public function __construct(string $message, mixed $body)
|
||||
{
|
||||
parent::__construct($message, -1);
|
||||
|
||||
$this->body = (array) $body;
|
||||
}
|
||||
}
|
||||
7
vendor/overtrue/socialite/src/Exceptions/BadRequestException.php
vendored
Normal file
7
vendor/overtrue/socialite/src/Exceptions/BadRequestException.php
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Exceptions;
|
||||
|
||||
class BadRequestException extends Exception
|
||||
{
|
||||
}
|
||||
8
vendor/overtrue/socialite/src/Exceptions/Exception.php
vendored
Normal file
8
vendor/overtrue/socialite/src/Exceptions/Exception.php
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Exceptions;
|
||||
|
||||
class Exception extends \Exception
|
||||
{
|
||||
//
|
||||
}
|
||||
9
vendor/overtrue/socialite/src/Exceptions/FeiShu/InvalidTicketException.php
vendored
Normal file
9
vendor/overtrue/socialite/src/Exceptions/FeiShu/InvalidTicketException.php
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Exceptions\FeiShu;
|
||||
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
|
||||
class InvalidTicketException extends Exceptions\Exception
|
||||
{
|
||||
}
|
||||
8
vendor/overtrue/socialite/src/Exceptions/InvalidArgumentException.php
vendored
Normal file
8
vendor/overtrue/socialite/src/Exceptions/InvalidArgumentException.php
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Exceptions;
|
||||
|
||||
class InvalidArgumentException extends \InvalidArgumentException
|
||||
{
|
||||
//
|
||||
}
|
||||
18
vendor/overtrue/socialite/src/Exceptions/InvalidTokenException.php
vendored
Normal file
18
vendor/overtrue/socialite/src/Exceptions/InvalidTokenException.php
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Exceptions;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
|
||||
class InvalidTokenException extends Exception
|
||||
{
|
||||
public string $token;
|
||||
|
||||
#[Pure]
|
||||
public function __construct(string $message, string $token)
|
||||
{
|
||||
parent::__construct($message, -1);
|
||||
|
||||
$this->token = $token;
|
||||
}
|
||||
}
|
||||
8
vendor/overtrue/socialite/src/Exceptions/MethodDoesNotSupportException.php
vendored
Normal file
8
vendor/overtrue/socialite/src/Exceptions/MethodDoesNotSupportException.php
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Exceptions;
|
||||
|
||||
class MethodDoesNotSupportException extends Exception
|
||||
{
|
||||
//
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?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
135
vendor/overtrue/socialite/src/HasAttributes.php
vendored
@@ -1,135 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?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
|
||||
{
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?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
|
||||
{
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
@@ -1,585 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
220
vendor/overtrue/socialite/src/Providers/Alipay.php
vendored
Normal file
220
vendor/overtrue/socialite/src/Providers/Alipay.php
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/289/105656
|
||||
*/
|
||||
class Alipay extends Base
|
||||
{
|
||||
public const NAME = 'alipay';
|
||||
|
||||
protected string $baseUrl = 'https://openapi.alipay.com/gateway.do';
|
||||
|
||||
protected string $authUrl = 'https://openauth.alipay.com/oauth2/publicAppAuthorize.htm';
|
||||
|
||||
protected array $scopes = ['auth_user'];
|
||||
|
||||
protected string $apiVersion = '1.0';
|
||||
|
||||
protected string $signType = 'RSA2';
|
||||
|
||||
protected string $postCharset = 'UTF-8';
|
||||
|
||||
protected string $format = 'json';
|
||||
|
||||
protected bool $sandbox = false;
|
||||
|
||||
public function __construct(array $config)
|
||||
{
|
||||
parent::__construct($config);
|
||||
$this->sandbox = (bool) $this->config->get('sandbox', false);
|
||||
if ($this->sandbox) {
|
||||
$this->baseUrl = 'https://openapi.alipaydev.com/gateway.do';
|
||||
$this->authUrl = 'https://openauth.alipaydev.com/oauth2/publicAppAuthorize.htm';
|
||||
}
|
||||
}
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->authUrl);
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return $this->baseUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\BadRequestException
|
||||
*/
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$params = $this->getPublicFields('alipay.user.info.share');
|
||||
$params += ['auth_token' => $token];
|
||||
$params['sign'] = $this->generateSign($params);
|
||||
|
||||
$responseInstance = $this->getHttpClient()->post(
|
||||
$this->baseUrl,
|
||||
[
|
||||
'form_params' => $params,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/x-www-form-urlencoded;charset=utf-8',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (! empty($response['error_response'] ?? null) || empty($response['alipay_user_info_share_response'] ?? [])) {
|
||||
throw new Exceptions\BadRequestException((string) $responseInstance->getBody());
|
||||
}
|
||||
|
||||
return $response['alipay_user_info_share_response'];
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user['user_id'] ?? null,
|
||||
Contracts\ABNF_NAME => $user['nick_name'] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user[Contracts\ABNF_AVATAR] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\BadRequestException
|
||||
*/
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
$responseInstance = $this->getHttpClient()->post(
|
||||
$this->getTokenUrl(),
|
||||
[
|
||||
'form_params' => $this->getTokenFields($code),
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/x-www-form-urlencoded;charset=utf-8',
|
||||
],
|
||||
]
|
||||
);
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (! empty($response['error_response'])) {
|
||||
throw new Exceptions\BadRequestException((string) $responseInstance->getBody());
|
||||
}
|
||||
|
||||
return $this->normalizeAccessTokenResponse($response['alipay_system_oauth_token_response']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\InvalidArgumentException
|
||||
*/
|
||||
protected function getCodeFields(): array
|
||||
{
|
||||
if (empty($this->redirectUrl)) {
|
||||
throw new Exceptions\InvalidArgumentException('Please set the correct redirect URL refer which was on the Alipay Official Admin pannel.');
|
||||
}
|
||||
|
||||
$fields = \array_merge(
|
||||
[
|
||||
Contracts\ABNF_APP_ID => $this->getConfig()->get(Contracts\RFC6749_ABNF_CLIENT_ID) ?? $this->getConfig()->get(Contracts\ABNF_APP_ID),
|
||||
Contracts\RFC6749_ABNF_SCOPE => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
],
|
||||
$this->parameters
|
||||
);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
$params = $this->getPublicFields('alipay.system.oauth.token');
|
||||
$params += [
|
||||
Contracts\RFC6749_ABNF_CODE => $code,
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
];
|
||||
$params['sign'] = $this->generateSign($params);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\ABNF_APP_ID => 'string',
|
||||
'format' => 'string',
|
||||
'charset' => 'string',
|
||||
'sign_type' => 'string',
|
||||
'method' => 'string',
|
||||
'timestamp' => 'string',
|
||||
'version' => 'string',
|
||||
])]
|
||||
public function getPublicFields(string $method): array
|
||||
{
|
||||
return [
|
||||
Contracts\ABNF_APP_ID => $this->getConfig()->get(Contracts\RFC6749_ABNF_CLIENT_ID) ?? $this->getConfig()->get(Contracts\ABNF_APP_ID),
|
||||
'format' => $this->format,
|
||||
'charset' => $this->postCharset,
|
||||
'sign_type' => $this->signType,
|
||||
'method' => $method,
|
||||
'timestamp' => (new \DateTime('now', new \DateTimeZone('Asia/Shanghai')))->format('Y-m-d H:i:s'),
|
||||
'version' => $this->apiVersion,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://opendocs.alipay.com/open/289/105656
|
||||
*/
|
||||
protected function generateSign(array $params): string
|
||||
{
|
||||
\ksort($params);
|
||||
|
||||
return $this->signWithSHA256RSA($this->buildParams($params), $this->getConfig()->get('rsa_private_key'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\InvalidArgumentException
|
||||
*/
|
||||
protected function signWithSHA256RSA(string $signContent, string $key): string
|
||||
{
|
||||
if (empty($key)) {
|
||||
throw new Exceptions\InvalidArgumentException('no RSA private key set.');
|
||||
}
|
||||
|
||||
$key = "-----BEGIN RSA PRIVATE KEY-----\n".
|
||||
\chunk_split($key, 64, "\n").
|
||||
'-----END RSA PRIVATE KEY-----';
|
||||
|
||||
\openssl_sign($signContent, $signValue, $key, \OPENSSL_ALGO_SHA256);
|
||||
|
||||
return \base64_encode($signValue);
|
||||
}
|
||||
|
||||
public static function buildParams(array $params, bool $urlencode = false, array $except = ['sign']): string
|
||||
{
|
||||
$param_str = '';
|
||||
foreach ($params as $k => $v) {
|
||||
if (\in_array($k, $except)) {
|
||||
continue;
|
||||
}
|
||||
$param_str .= $k.'=';
|
||||
$param_str .= $urlencode ? \rawurlencode($v) : $v;
|
||||
$param_str .= '&';
|
||||
}
|
||||
|
||||
return \rtrim($param_str, '&');
|
||||
}
|
||||
}
|
||||
72
vendor/overtrue/socialite/src/Providers/Azure.php
vendored
Normal file
72
vendor/overtrue/socialite/src/Providers/Azure.php
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
class Azure extends Base
|
||||
{
|
||||
public const NAME = 'azure';
|
||||
|
||||
protected array $scopes = ['User.Read'];
|
||||
|
||||
protected string $scopeSeparator = ' ';
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->getBaseUrl().'/oauth2/v2.0/authorize');
|
||||
}
|
||||
|
||||
protected function getBaseUrl(): string
|
||||
{
|
||||
return 'https://login.microsoftonline.com/'.$this->config['tenant'];
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return $this->getBaseUrl().'/oauth2/v2.0/token';
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token, ?array $query = []): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get(
|
||||
'https://graph.microsoft.com/v1.0/me',
|
||||
['headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_ID] ?? null,
|
||||
Contracts\ABNF_NICKNAME => null,
|
||||
Contracts\ABNF_NAME => $user['displayName'] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user['userPrincipalName'] ?? null,
|
||||
Contracts\ABNF_AVATAR => null,
|
||||
]);
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return parent::getTokenFields($code) + [
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
];
|
||||
}
|
||||
}
|
||||
102
vendor/overtrue/socialite/src/Providers/Baidu.php
vendored
Normal file
102
vendor/overtrue/socialite/src/Providers/Baidu.php
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see https://developer.baidu.com/wiki/index.php?title=docs/oauth [OAuth 2.0 授权机制说明]
|
||||
*/
|
||||
class Baidu extends Base
|
||||
{
|
||||
public const NAME = 'baidu';
|
||||
|
||||
protected string $baseUrl = 'https://openapi.baidu.com';
|
||||
|
||||
protected string $version = '2.0';
|
||||
|
||||
protected array $scopes = ['basic'];
|
||||
|
||||
protected string $display = 'popup';
|
||||
|
||||
public function withDisplay(string $display): self
|
||||
{
|
||||
$this->display = $display;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withScopes(array $scopes): self
|
||||
{
|
||||
$this->scopes = $scopes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth/'.$this->version.'/authorize');
|
||||
}
|
||||
|
||||
protected function getCodeFields(): array
|
||||
{
|
||||
return [
|
||||
Contracts\RFC6749_ABNF_RESPONSE_TYPE => Contracts\RFC6749_ABNF_CODE,
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => $this->getClientId(),
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
Contracts\RFC6749_ABNF_SCOPE => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
'display' => $this->display,
|
||||
] + $this->parameters;
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return $this->baseUrl.'/oauth/'.$this->version.'/token';
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return parent::getTokenFields($code) + [
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get(
|
||||
$this->baseUrl.'/rest/'.$this->version.'/passport/users/getInfo',
|
||||
[
|
||||
'query' => [
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $token,
|
||||
],
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user['userid'] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user['realname'] ?? null,
|
||||
Contracts\ABNF_NAME => $user['username'] ?? null,
|
||||
Contracts\ABNF_EMAIL => '',
|
||||
Contracts\ABNF_AVATAR => $user['portrait'] ? 'http://tb.himg.baidu.com/sys/portraitn/item/'.$user['portrait'] : null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
<?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'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
284
vendor/overtrue/socialite/src/Providers/Base.php
vendored
Normal file
284
vendor/overtrue/socialite/src/Providers/Base.php
vendored
Normal file
@@ -0,0 +1,284 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
use GuzzleHttp\Utils;
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use Overtrue\Socialite\Config;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Psr\Http\Message\MessageInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
abstract class Base implements Contracts\ProviderInterface
|
||||
{
|
||||
public const NAME = null;
|
||||
|
||||
protected ?string $state = null;
|
||||
|
||||
protected Config $config;
|
||||
|
||||
protected ?string $redirectUrl;
|
||||
|
||||
protected array $parameters = [];
|
||||
|
||||
protected array $scopes = [];
|
||||
|
||||
protected string $scopeSeparator = ',';
|
||||
|
||||
protected GuzzleClient $httpClient;
|
||||
|
||||
protected array $guzzleOptions = [];
|
||||
|
||||
protected int $encodingType = PHP_QUERY_RFC1738;
|
||||
|
||||
protected string $expiresInKey = Contracts\RFC6749_ABNF_EXPIRES_IN;
|
||||
|
||||
protected string $accessTokenKey = Contracts\RFC6749_ABNF_ACCESS_TOKEN;
|
||||
|
||||
protected string $refreshTokenKey = Contracts\RFC6749_ABNF_REFRESH_TOKEN;
|
||||
|
||||
public function __construct(array $config)
|
||||
{
|
||||
$this->config = new Config($config);
|
||||
|
||||
// set scopes
|
||||
if ($this->config->has('scopes') && is_array($this->config->get('scopes'))) {
|
||||
$this->scopes = $this->getConfig()->get('scopes');
|
||||
} elseif ($this->config->has(Contracts\RFC6749_ABNF_SCOPE) && is_string($this->getConfig()->get(Contracts\RFC6749_ABNF_SCOPE))) {
|
||||
$this->scopes = [$this->getConfig()->get(Contracts\RFC6749_ABNF_SCOPE)];
|
||||
}
|
||||
|
||||
// normalize Contracts\RFC6749_ABNF_CLIENT_ID
|
||||
if (! $this->config->has(Contracts\RFC6749_ABNF_CLIENT_ID)) {
|
||||
$id = $this->config->get(Contracts\ABNF_APP_ID);
|
||||
if (null != $id) {
|
||||
$this->config->set(Contracts\RFC6749_ABNF_CLIENT_ID, $id);
|
||||
}
|
||||
}
|
||||
|
||||
// normalize Contracts\RFC6749_ABNF_CLIENT_SECRET
|
||||
if (! $this->config->has(Contracts\RFC6749_ABNF_CLIENT_SECRET)) {
|
||||
$secret = $this->config->get(Contracts\ABNF_APP_SECRET);
|
||||
if (null != $secret) {
|
||||
$this->config->set(Contracts\RFC6749_ABNF_CLIENT_SECRET, $secret);
|
||||
}
|
||||
}
|
||||
|
||||
// normalize 'redirect_url'
|
||||
if (! $this->config->has('redirect_url')) {
|
||||
$this->config->set('redirect_url', $this->config->get('redirect'));
|
||||
}
|
||||
$this->redirectUrl = $this->config->get('redirect_url');
|
||||
}
|
||||
|
||||
abstract protected function getAuthUrl(): string;
|
||||
|
||||
abstract protected function getTokenUrl(): string;
|
||||
|
||||
abstract protected function getUserByToken(string $token): array;
|
||||
|
||||
abstract protected function mapUserToObject(array $user): Contracts\UserInterface;
|
||||
|
||||
public function redirect(?string $redirectUrl = null): string
|
||||
{
|
||||
if (! empty($redirectUrl)) {
|
||||
$this->withRedirectUrl($redirectUrl);
|
||||
}
|
||||
|
||||
return $this->getAuthUrl();
|
||||
}
|
||||
|
||||
public function userFromCode(string $code): Contracts\UserInterface
|
||||
{
|
||||
$tokenResponse = $this->tokenFromCode($code);
|
||||
$user = $this->userFromToken($tokenResponse[$this->accessTokenKey]);
|
||||
|
||||
return $user->setRefreshToken($tokenResponse[$this->refreshTokenKey] ?? null)
|
||||
->setExpiresIn($tokenResponse[$this->expiresInKey] ?? null)
|
||||
->setTokenResponse($tokenResponse);
|
||||
}
|
||||
|
||||
public function userFromToken(string $token): Contracts\UserInterface
|
||||
{
|
||||
$user = $this->getUserByToken($token);
|
||||
|
||||
return $this->mapUserToObject($user)->setProvider($this)->setRaw($user)->setAccessToken($token);
|
||||
}
|
||||
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
$response = $this->getHttpClient()->post(
|
||||
$this->getTokenUrl(),
|
||||
[
|
||||
'form_params' => $this->getTokenFields($code),
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return $this->normalizeAccessTokenResponse((string) $response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\MethodDoesNotSupportException
|
||||
*/
|
||||
public function refreshToken(string $refreshToken): void
|
||||
{
|
||||
throw new Exceptions\MethodDoesNotSupportException('refreshToken does not support.');
|
||||
}
|
||||
|
||||
public function withRedirectUrl(string $redirectUrl): Contracts\ProviderInterface
|
||||
{
|
||||
$this->redirectUrl = $redirectUrl;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withState(string $state): Contracts\ProviderInterface
|
||||
{
|
||||
$this->state = $state;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function scopes(array $scopes): Contracts\ProviderInterface
|
||||
{
|
||||
$this->scopes = $scopes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function with(array $parameters): Contracts\ProviderInterface
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getConfig(): Config
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
public function withScopeSeparator(string $scopeSeparator): Contracts\ProviderInterface
|
||||
{
|
||||
$this->scopeSeparator = $scopeSeparator;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getClientId(): ?string
|
||||
{
|
||||
return $this->config->get(Contracts\RFC6749_ABNF_CLIENT_ID);
|
||||
}
|
||||
|
||||
public function getClientSecret(): ?string
|
||||
{
|
||||
return $this->config->get(Contracts\RFC6749_ABNF_CLIENT_SECRET);
|
||||
}
|
||||
|
||||
public function getHttpClient(): GuzzleClient
|
||||
{
|
||||
return $this->httpClient ?? new GuzzleClient($this->guzzleOptions);
|
||||
}
|
||||
|
||||
public function setGuzzleOptions(array $config): Contracts\ProviderInterface
|
||||
{
|
||||
$this->guzzleOptions = $config;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getGuzzleOptions(): array
|
||||
{
|
||||
return $this->guzzleOptions;
|
||||
}
|
||||
|
||||
protected function formatScopes(array $scopes, string $scopeSeparator): string
|
||||
{
|
||||
return \implode($scopeSeparator, $scopes);
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return [
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => $this->getClientId(),
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => $this->getClientSecret(),
|
||||
Contracts\RFC6749_ABNF_CODE => $code,
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
];
|
||||
}
|
||||
|
||||
protected function buildAuthUrlFromBase(string $url): string
|
||||
{
|
||||
$query = $this->getCodeFields() + ($this->state ? [Contracts\RFC6749_ABNF_STATE => $this->state] : []);
|
||||
|
||||
return $url.'?'.\http_build_query($query, '', '&', $this->encodingType);
|
||||
}
|
||||
|
||||
protected function getCodeFields(): array
|
||||
{
|
||||
$fields = \array_merge(
|
||||
[
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => $this->getClientId(),
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
Contracts\RFC6749_ABNF_SCOPE => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
Contracts\RFC6749_ABNF_RESPONSE_TYPE => Contracts\RFC6749_ABNF_CODE,
|
||||
],
|
||||
$this->parameters
|
||||
);
|
||||
|
||||
if ($this->state) {
|
||||
$fields[Contracts\RFC6749_ABNF_STATE] = $this->state;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
*/
|
||||
protected function normalizeAccessTokenResponse(mixed $response): array
|
||||
{
|
||||
if ($response instanceof StreamInterface) {
|
||||
$response->tell() && $response->rewind();
|
||||
$response = (string) $response;
|
||||
}
|
||||
|
||||
if (\is_string($response)) {
|
||||
$response = Utils::jsonDecode($response, true);
|
||||
}
|
||||
|
||||
if (! \is_array($response)) {
|
||||
throw new Exceptions\AuthorizeFailedException('Invalid token response', [$response]);
|
||||
}
|
||||
|
||||
if (empty($response[$this->accessTokenKey])) {
|
||||
throw new Exceptions\AuthorizeFailedException('Authorize Failed: '.Utils::jsonEncode($response, \JSON_UNESCAPED_UNICODE), $response);
|
||||
}
|
||||
|
||||
return $response + [
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $response[$this->accessTokenKey],
|
||||
Contracts\RFC6749_ABNF_REFRESH_TOKEN => $response[$this->refreshTokenKey] ?? null,
|
||||
Contracts\RFC6749_ABNF_EXPIRES_IN => \intval($response[$this->expiresInKey] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
protected function fromJsonBody(MessageInterface $response): array
|
||||
{
|
||||
$result = Utils::jsonDecode((string) $response->getBody(), true);
|
||||
|
||||
\is_array($result) || throw new Exceptions\InvalidArgumentException('Decoded the given response payload failed.');
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
103
vendor/overtrue/socialite/src/Providers/Coding.php
vendored
Normal file
103
vendor/overtrue/socialite/src/Providers/Coding.php
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Overtrue\Socialite\Exceptions\InvalidArgumentException;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
class Coding extends Base
|
||||
{
|
||||
public const NAME = 'coding';
|
||||
|
||||
// example: https://{your-team}.coding.net
|
||||
protected string $teamUrl;
|
||||
|
||||
protected array $scopes = ['user', 'user:email'];
|
||||
|
||||
protected string $scopeSeparator = ',';
|
||||
|
||||
public function __construct(array $config)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
// https://{your-team}.coding.net
|
||||
$teamUrl = $this->config->get('team_url');
|
||||
|
||||
if (! $teamUrl) {
|
||||
throw new InvalidArgumentException('Missing required config [team_url]');
|
||||
}
|
||||
|
||||
// validate team_url
|
||||
if (filter_var($teamUrl, FILTER_VALIDATE_URL) === false) {
|
||||
throw new InvalidArgumentException('Invalid team_url');
|
||||
}
|
||||
|
||||
$this->teamUrl = rtrim($teamUrl, '/');
|
||||
}
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase("$this->teamUrl/oauth_authorize.html");
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return "$this->teamUrl/api/oauth/access_token";
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'null|string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return [
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => $this->getClientId(),
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => $this->getClientSecret(),
|
||||
Contracts\RFC6749_ABNF_CODE => $code,
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
* @throws \Overtrue\Socialite\Exceptions\BadRequestException
|
||||
*/
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$responseInstance = $this->getHttpClient()->get(
|
||||
"$this->teamUrl/api/me",
|
||||
[
|
||||
'query' => [
|
||||
'access_token' => $token,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (empty($response[Contracts\ABNF_ID])) {
|
||||
throw new Exceptions\BadRequestException((string) $responseInstance->getBody());
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_ID] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user[Contracts\ABNF_AVATAR] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
123
vendor/overtrue/socialite/src/Providers/DingTalk.php
vendored
Normal file
123
vendor/overtrue/socialite/src/Providers/DingTalk.php
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* “第三方个人应用”获取用户信息
|
||||
*
|
||||
* @see https://ding-doc.dingtalk.com/doc#/serverapi3/mrugr3
|
||||
*
|
||||
* 暂不支持“第三方企业应用”获取用户信息
|
||||
* @see https://ding-doc.dingtalk.com/doc#/serverapi3/hv357q
|
||||
*/
|
||||
class DingTalk extends Base
|
||||
{
|
||||
public const NAME = 'dingtalk';
|
||||
|
||||
protected string $getUserByCode = 'https://oapi.dingtalk.com/sns/getuserinfo_bycode';
|
||||
|
||||
protected array $scopes = ['snsapi_login'];
|
||||
|
||||
protected string $scopeSeparator = ' ';
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://oapi.dingtalk.com/connect/qrconnect');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\InvalidArgumentException
|
||||
*/
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
throw new Exceptions\InvalidArgumentException('not supported to get access token.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\InvalidArgumentException
|
||||
*/
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
throw new Exceptions\InvalidArgumentException('Unable to use token get User.');
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_NAME => $user['nick'] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user['nick'] ?? null,
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_OPEN_ID] ?? null,
|
||||
Contracts\ABNF_EMAIL => null,
|
||||
Contracts\ABNF_AVATAR => null,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getCodeFields(): array
|
||||
{
|
||||
return array_merge(
|
||||
[
|
||||
'appid' => $this->getClientId(),
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
Contracts\RFC6749_ABNF_CODE => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
],
|
||||
$this->parameters
|
||||
);
|
||||
}
|
||||
|
||||
public function getClientId(): ?string
|
||||
{
|
||||
return $this->getConfig()->get(Contracts\ABNF_APP_ID)
|
||||
?? $this->getConfig()->get('appid')
|
||||
?? $this->getConfig()->get('appId')
|
||||
?? $this->getConfig()->get(Contracts\RFC6749_ABNF_CLIENT_ID);
|
||||
}
|
||||
|
||||
public function getClientSecret(): ?string
|
||||
{
|
||||
return $this->getConfig()->get(Contracts\ABNF_APP_SECRET)
|
||||
?? $this->getConfig()->get('appSecret')
|
||||
?? $this->getConfig()->get(Contracts\RFC6749_ABNF_CLIENT_SECRET);
|
||||
}
|
||||
|
||||
protected function createSignature(int $time): string
|
||||
{
|
||||
return \base64_encode(\hash_hmac('sha256', (string) $time, (string) $this->getClientSecret(), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://ding-doc.dingtalk.com/doc#/personnal/tmudue
|
||||
*
|
||||
* @throws Exceptions\BadRequestException
|
||||
*/
|
||||
public function userFromCode(string $code): Contracts\UserInterface
|
||||
{
|
||||
$time = (int) \microtime(true) * 1000;
|
||||
|
||||
$responseInstance = $this->getHttpClient()->post($this->getUserByCode, [
|
||||
'query' => [
|
||||
'accessKey' => $this->getClientId(),
|
||||
'timestamp' => $time,
|
||||
'signature' => $this->createSignature($time),
|
||||
],
|
||||
'json' => ['tmp_auth_code' => $code],
|
||||
]);
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (0 != ($response['errcode'] ?? 1)) {
|
||||
throw new Exceptions\BadRequestException((string) $responseInstance->getBody());
|
||||
}
|
||||
|
||||
return new User([
|
||||
Contracts\ABNF_NAME => $response['user_info']['nick'],
|
||||
Contracts\ABNF_NICKNAME => $response['user_info']['nick'],
|
||||
Contracts\ABNF_ID => $response['user_info'][Contracts\ABNF_OPEN_ID],
|
||||
]);
|
||||
}
|
||||
}
|
||||
134
vendor/overtrue/socialite/src/Providers/DouYin.php
vendored
Normal file
134
vendor/overtrue/socialite/src/Providers/DouYin.php
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see http://open.douyin.com/platform
|
||||
* @see https://open.douyin.com/platform/doc/OpenAPI-overview
|
||||
*/
|
||||
class DouYin extends Base
|
||||
{
|
||||
public const NAME = 'douyin';
|
||||
|
||||
protected string $baseUrl = 'https://open.douyin.com';
|
||||
|
||||
protected array $scopes = ['user_info'];
|
||||
|
||||
protected ?string $openId;
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/platform/oauth/connect/');
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
'client_key' => 'null|string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_SCOPE => 'string',
|
||||
Contracts\RFC6749_ABNF_RESPONSE_TYPE => 'string',
|
||||
])]
|
||||
public function getCodeFields(): array
|
||||
{
|
||||
return [
|
||||
'client_key' => $this->getClientId(),
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
Contracts\RFC6749_ABNF_SCOPE => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
Contracts\RFC6749_ABNF_RESPONSE_TYPE => Contracts\RFC6749_ABNF_CODE,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return $this->baseUrl.'/oauth/access_token/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
*/
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get(
|
||||
$this->getTokenUrl(),
|
||||
[
|
||||
'query' => $this->getTokenFields($code),
|
||||
]
|
||||
);
|
||||
|
||||
$body = $this->fromJsonBody($response);
|
||||
|
||||
if (empty($body['data'] ?? null) || ($body['data']['error_code'] ?? -1) != 0) {
|
||||
throw new Exceptions\AuthorizeFailedException('Invalid token response', $body);
|
||||
}
|
||||
|
||||
$this->withOpenId($body['data'][Contracts\ABNF_OPEN_ID]);
|
||||
|
||||
return $this->normalizeAccessTokenResponse($body['data']);
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
'client_key' => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return [
|
||||
'client_key' => $this->getClientId(),
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => $this->getClientSecret(),
|
||||
Contracts\RFC6749_ABNF_CODE => $code,
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\InvalidArgumentException
|
||||
*/
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$userUrl = $this->baseUrl.'/oauth/userinfo/';
|
||||
|
||||
if (empty($this->openId)) {
|
||||
throw new Exceptions\InvalidArgumentException('please set the `open_id` before issue the API request.');
|
||||
}
|
||||
|
||||
$response = $this->getHttpClient()->get(
|
||||
$userUrl,
|
||||
[
|
||||
'query' => [
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $token,
|
||||
Contracts\ABNF_OPEN_ID => $this->openId,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$body = $this->fromJsonBody($response);
|
||||
|
||||
return $body['data'] ?? [];
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_OPEN_ID] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NICKNAME] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user[Contracts\ABNF_NICKNAME] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user[Contracts\ABNF_AVATAR] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function withOpenId(string $openId): self
|
||||
{
|
||||
$this->openId = $openId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
<?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'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
74
vendor/overtrue/socialite/src/Providers/Douban.php
vendored
Normal file
74
vendor/overtrue/socialite/src/Providers/Douban.php
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see http://developers.douban.com/wiki/?title=oauth2 [使用 OAuth 2.0 访问豆瓣 API]
|
||||
*/
|
||||
class Douban extends Base
|
||||
{
|
||||
public const NAME = 'douban';
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://www.douban.com/service/auth2/auth');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return 'https://www.douban.com/service/auth2/token';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
* @param ?array $query
|
||||
*/
|
||||
protected function getUserByToken(string $token, ?array $query = []): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get('https://api.douban.com/v2/user/~me', [
|
||||
'headers' => [
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
],
|
||||
]);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_ID] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user[Contracts\ABNF_AVATAR] ?? null,
|
||||
Contracts\ABNF_EMAIL => null,
|
||||
]);
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return parent::getTokenFields($code) + [Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE];
|
||||
}
|
||||
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'form_params' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->normalizeAccessTokenResponse($response->getBody());
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?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());
|
||||
}
|
||||
}
|
||||
106
vendor/overtrue/socialite/src/Providers/Facebook.php
vendored
Normal file
106
vendor/overtrue/socialite/src/Providers/Facebook.php
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see https://developers.facebook.com/docs/graph-api [Facebook - Graph API]
|
||||
*/
|
||||
class Facebook extends Base
|
||||
{
|
||||
public const NAME = 'facebook';
|
||||
|
||||
protected string $graphUrl = 'https://graph.facebook.com';
|
||||
|
||||
protected string $version = 'v3.3';
|
||||
|
||||
protected array $fields = ['first_name', 'last_name', 'email', 'gender', 'verified'];
|
||||
|
||||
protected array $scopes = ['email'];
|
||||
|
||||
protected bool $popup = false;
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://www.facebook.com/'.$this->version.'/dialog/oauth');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return $this->graphUrl.'/oauth/access_token';
|
||||
}
|
||||
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->getTokenUrl(), [
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->normalizeAccessTokenResponse($response->getBody());
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token, ?array $query = []): array
|
||||
{
|
||||
$appSecretProof = \hash_hmac('sha256', $token, $this->getConfig()->get(Contracts\RFC6749_ABNF_CLIENT_SECRET));
|
||||
|
||||
$response = $this->getHttpClient()->get($this->graphUrl.'/'.$this->version.'/me', [
|
||||
'query' => [
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $token,
|
||||
'appsecret_proof' => $appSecretProof,
|
||||
'fields' => $this->formatScopes($this->fields, $this->scopeSeparator),
|
||||
],
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
$userId = $user[Contracts\ABNF_ID] ?? null;
|
||||
$avatarUrl = $this->graphUrl.'/'.$this->version.'/'.$userId.'/picture';
|
||||
|
||||
$firstName = $user['first_name'] ?? null;
|
||||
$lastName = $user['last_name'] ?? null;
|
||||
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_ID] ?? null,
|
||||
Contracts\ABNF_NICKNAME => null,
|
||||
Contracts\ABNF_NAME => $firstName.' '.$lastName,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
Contracts\ABNF_AVATAR => $userId ? $avatarUrl.'?type=normal' : null,
|
||||
'avatar_original' => $userId ? $avatarUrl.'?width=1920' : null,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getCodeFields(): array
|
||||
{
|
||||
$fields = parent::getCodeFields();
|
||||
|
||||
if ($this->popup) {
|
||||
$fields['display'] = 'popup';
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function fields(array $fields): self
|
||||
{
|
||||
$this->fields = $fields;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function asPopup(): self
|
||||
{
|
||||
$this->popup = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
228
vendor/overtrue/socialite/src/Providers/FeiShu.php
vendored
Normal file
228
vendor/overtrue/socialite/src/Providers/FeiShu.php
vendored
Normal file
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see https://open.feishu.cn/document/uQjL04CN/ucDOz4yN4MjL3gzM
|
||||
*/
|
||||
class FeiShu extends Base
|
||||
{
|
||||
public const NAME = 'feishu';
|
||||
|
||||
private const APP_TICKET = 'app_ticket';
|
||||
|
||||
protected string $baseUrl = 'https://open.feishu.cn/open-apis';
|
||||
|
||||
protected string $expiresInKey = 'refresh_expires_in';
|
||||
|
||||
protected bool $isInternalApp = false;
|
||||
|
||||
public function __construct(array $config)
|
||||
{
|
||||
parent::__construct($config);
|
||||
$this->isInternalApp = ($this->config->get('app_mode') ?? $this->config->get('mode')) == 'internal';
|
||||
}
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/authen/v1/index');
|
||||
}
|
||||
|
||||
#[ArrayShape([Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string', Contracts\ABNF_APP_ID => 'null|string'])]
|
||||
protected function getCodeFields(): array
|
||||
{
|
||||
return [
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
Contracts\ABNF_APP_ID => $this->getClientId(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return $this->baseUrl.'/authen/v1/access_token';
|
||||
}
|
||||
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
return $this->normalizeAccessTokenResponse($this->getTokenFromCode($code));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
*/
|
||||
protected function getTokenFromCode(string $code): array
|
||||
{
|
||||
$this->configAppAccessToken();
|
||||
$responseInstance = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'json' => [
|
||||
'app_access_token' => $this->config->get('app_access_token'),
|
||||
Contracts\RFC6749_ABNF_CODE => $code,
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
],
|
||||
]);
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (empty($response['data'] ?? null)) {
|
||||
throw new Exceptions\AuthorizeFailedException('Invalid token response', $response);
|
||||
}
|
||||
|
||||
return $this->normalizeAccessTokenResponse($response['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\BadRequestException
|
||||
*/
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$responseInstance = $this->getHttpClient()->get($this->baseUrl.'/authen/v1/user_info', [
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
],
|
||||
'query' => \array_filter(
|
||||
[
|
||||
'user_access_token' => $token,
|
||||
]
|
||||
),
|
||||
]);
|
||||
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (empty($response['data'] ?? null)) {
|
||||
throw new Exceptions\BadRequestException((string) $responseInstance->getBody());
|
||||
}
|
||||
|
||||
return $response['data'];
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user['user_id'] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user['avatar_url'] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function withInternalAppMode(): self
|
||||
{
|
||||
$this->isInternalApp = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withDefaultMode(): self
|
||||
{
|
||||
$this->isInternalApp = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* set self::APP_TICKET in config attribute
|
||||
*/
|
||||
public function withAppTicket(string $appTicket): self
|
||||
{
|
||||
$this->config->set(self::APP_TICKET, $appTicket);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 app_access_token 到 config 设置中
|
||||
* 应用维度授权凭证,开放平台可据此识别调用方的应用身份
|
||||
* 分内建和自建
|
||||
*
|
||||
* @throws Exceptions\FeiShu\InvalidTicketException
|
||||
* @throws Exceptions\InvalidTokenException
|
||||
*/
|
||||
protected function configAppAccessToken(): self
|
||||
{
|
||||
$url = $this->baseUrl.'/auth/v3/app_access_token/';
|
||||
$params = [
|
||||
'json' => [
|
||||
Contracts\ABNF_APP_ID => $this->config->get(Contracts\RFC6749_ABNF_CLIENT_ID),
|
||||
Contracts\ABNF_APP_SECRET => $this->config->get(Contracts\RFC6749_ABNF_CLIENT_SECRET),
|
||||
self::APP_TICKET => $this->config->get(self::APP_TICKET),
|
||||
],
|
||||
];
|
||||
|
||||
if ($this->isInternalApp) {
|
||||
$url = $this->baseUrl.'/auth/v3/app_access_token/internal/';
|
||||
$params = [
|
||||
'json' => [
|
||||
Contracts\ABNF_APP_ID => $this->config->get(Contracts\RFC6749_ABNF_CLIENT_ID),
|
||||
Contracts\ABNF_APP_SECRET => $this->config->get(Contracts\RFC6749_ABNF_CLIENT_SECRET),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
if (! $this->isInternalApp && ! $this->config->has(self::APP_TICKET)) {
|
||||
throw new Exceptions\FeiShu\InvalidTicketException('You are using default mode, please config \'app_ticket\' first');
|
||||
}
|
||||
|
||||
$responseInstance = $this->getHttpClient()->post($url, $params);
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (empty($response['app_access_token'] ?? null)) {
|
||||
throw new Exceptions\InvalidTokenException('Invalid \'app_access_token\' response', (string) $responseInstance->getBody());
|
||||
}
|
||||
|
||||
$this->config->set('app_access_token', $response['app_access_token']);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 tenant_access_token 到 config 属性中
|
||||
* 应用的企业授权凭证,开放平台据此识别调用方的应用身份和企业身份
|
||||
* 分内建和自建
|
||||
*
|
||||
* @throws Exceptions\BadRequestException
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
*/
|
||||
protected function configTenantAccessToken(): self
|
||||
{
|
||||
$url = $this->baseUrl.'/auth/v3/tenant_access_token/';
|
||||
$params = [
|
||||
'json' => [
|
||||
Contracts\ABNF_APP_ID => $this->config->get(Contracts\RFC6749_ABNF_CLIENT_ID),
|
||||
Contracts\ABNF_APP_SECRET => $this->config->get(Contracts\RFC6749_ABNF_CLIENT_SECRET),
|
||||
self::APP_TICKET => $this->config->get(self::APP_TICKET),
|
||||
],
|
||||
];
|
||||
|
||||
if ($this->isInternalApp) {
|
||||
$url = $this->baseUrl.'/auth/v3/tenant_access_token/internal/';
|
||||
$params = [
|
||||
'json' => [
|
||||
Contracts\ABNF_APP_ID => $this->config->get(Contracts\RFC6749_ABNF_CLIENT_ID),
|
||||
Contracts\ABNF_APP_SECRET => $this->config->get(Contracts\RFC6749_ABNF_CLIENT_SECRET),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
if (! $this->isInternalApp && ! $this->config->has(self::APP_TICKET)) {
|
||||
throw new Exceptions\BadRequestException('You are using default mode, please config \'app_ticket\' first');
|
||||
}
|
||||
|
||||
$response = $this->getHttpClient()->post($url, $params);
|
||||
$response = $this->fromJsonBody($response);
|
||||
if (empty($response['tenant_access_token'])) {
|
||||
throw new Exceptions\AuthorizeFailedException('Invalid tenant_access_token response', $response);
|
||||
}
|
||||
|
||||
$this->config->set('tenant_access_token', $response['tenant_access_token']);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
<?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'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
81
vendor/overtrue/socialite/src/Providers/Figma.php
vendored
Normal file
81
vendor/overtrue/socialite/src/Providers/Figma.php
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see https://www.figma.com/developers/api#oauth2
|
||||
*/
|
||||
class Figma extends Base
|
||||
{
|
||||
public const NAME = 'figma';
|
||||
|
||||
protected string $scopeSeparator = '';
|
||||
|
||||
protected array $scopes = ['file_read'];
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://www.figma.com/oauth');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return 'https://www.figma.com/api/oauth/token';
|
||||
}
|
||||
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'form_params' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->normalizeAccessTokenResponse($response->getBody());
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return parent::getTokenFields($code) + [Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE];
|
||||
}
|
||||
|
||||
protected function getCodeFields(): array
|
||||
{
|
||||
return parent::getCodeFields() + [Contracts\RFC6749_ABNF_STATE => \md5(\uniqid('state_', true))];
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token, ?array $query = []): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get('https://api.figma.com/v1/me', [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
],
|
||||
]);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_ID] ?? null,
|
||||
'username' => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user['handle'] ?? null,
|
||||
Contracts\ABNF_NAME => $user['handle'] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user['img_url'] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
90
vendor/overtrue/socialite/src/Providers/GitHub.php
vendored
Normal file
90
vendor/overtrue/socialite/src/Providers/GitHub.php
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
class GitHub extends Base
|
||||
{
|
||||
public const NAME = 'github';
|
||||
|
||||
protected array $scopes = ['read:user'];
|
||||
|
||||
protected string $scopeSeparator = ' ';
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://github.com/login/oauth/authorize');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return 'https://github.com/login/oauth/access_token';
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$userUrl = 'https://api.github.com/user';
|
||||
|
||||
$response = $this->getHttpClient()->get(
|
||||
$userUrl,
|
||||
$this->createAuthorizationHeaders($token)
|
||||
);
|
||||
|
||||
$user = $this->fromJsonBody($response);
|
||||
|
||||
if (\in_array('user:email', $this->scopes)) {
|
||||
$user[Contracts\ABNF_EMAIL] = $this->getEmailByToken($token);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
protected function getEmailByToken(string $token): string
|
||||
{
|
||||
$emailsUrl = 'https://api.github.com/user/emails';
|
||||
|
||||
try {
|
||||
$response = $this->getHttpClient()->get(
|
||||
$emailsUrl,
|
||||
$this->createAuthorizationHeaders($token)
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
return '';
|
||||
}
|
||||
|
||||
foreach ($this->fromJsonBody($response) as $email) {
|
||||
if ($email['primary'] && $email['verified']) {
|
||||
return $email[Contracts\ABNF_EMAIL];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_ID] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user['login'] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user['avatar_url'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
#[ArrayShape(['headers' => 'array'])]
|
||||
protected function createAuthorizationHeaders(string $token): array
|
||||
{
|
||||
return [
|
||||
'headers' => [
|
||||
'Accept' => 'application/vnd.github.v3+json',
|
||||
'Authorization' => \sprintf('token %s', $token),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
<?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),
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
67
vendor/overtrue/socialite/src/Providers/Gitee.php
vendored
Normal file
67
vendor/overtrue/socialite/src/Providers/Gitee.php
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
class Gitee extends Base
|
||||
{
|
||||
public const NAME = 'gitee';
|
||||
|
||||
protected array $scopes = ['user_info'];
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://gitee.com/oauth/authorize');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return 'https://gitee.com/oauth/token';
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$userUrl = 'https://gitee.com/api/v5/user';
|
||||
$response = $this->getHttpClient()->get($userUrl, [
|
||||
'query' => [
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $token,
|
||||
],
|
||||
]);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_ID] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user['login'] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user['avatar_url'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return [
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => $this->getClientId(),
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => $this->getClientSecret(),
|
||||
Contracts\RFC6749_ABNF_CODE => $code,
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
];
|
||||
}
|
||||
}
|
||||
79
vendor/overtrue/socialite/src/Providers/Google.php
vendored
Normal file
79
vendor/overtrue/socialite/src/Providers/Google.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see https://developers.google.com/identity/protocols/OpenIDConnect [OpenID Connect]
|
||||
*/
|
||||
class Google extends Base
|
||||
{
|
||||
public const NAME = 'google';
|
||||
|
||||
protected string $scopeSeparator = ' ';
|
||||
|
||||
protected array $scopes = [
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
];
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://accounts.google.com/o/oauth2/v2/auth');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return 'https://www.googleapis.com/oauth2/v4/token';
|
||||
}
|
||||
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'form_params' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->normalizeAccessTokenResponse($response->getBody());
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return parent::getTokenFields($code) + [Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE];
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token, ?array $query = []): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get('https://www.googleapis.com/userinfo/v2/me', [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
],
|
||||
]);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_ID] ?? null,
|
||||
'username' => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user['picture'] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
<?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'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
73
vendor/overtrue/socialite/src/Providers/Line.php
vendored
Normal file
73
vendor/overtrue/socialite/src/Providers/Line.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see https://developers.line.biz/en/docs/line-login/integrate-line-login/ [Integrating LINE Login with your web app]
|
||||
*/
|
||||
class Line extends Base
|
||||
{
|
||||
public const NAME = 'line';
|
||||
|
||||
protected string $baseUrl = 'https://api.line.me/oauth2/';
|
||||
|
||||
protected string $version = 'v2.1';
|
||||
|
||||
protected array $scopes = ['profile'];
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
$this->state = $this->state ?: \md5(\uniqid(Contracts\RFC6749_ABNF_STATE, true));
|
||||
|
||||
return $this->buildAuthUrlFromBase('https://access.line.me/oauth2/'.$this->version.'/authorize');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return $this->baseUrl.$this->version.'/token';
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return parent::getTokenFields($code) + [Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE];
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get(
|
||||
'https://api.line.me/v2/profile',
|
||||
[
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user['userId'] ?? null,
|
||||
Contracts\ABNF_NAME => $user['displayName'] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user['displayName'] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user['pictureUrl'] ?? null,
|
||||
Contracts\ABNF_EMAIL => null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
98
vendor/overtrue/socialite/src/Providers/Linkedin.php
vendored
Normal file
98
vendor/overtrue/socialite/src/Providers/Linkedin.php
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see https://developer.linkedin.com/docs/oauth2 [Authenticating with OAuth 2.0]
|
||||
*/
|
||||
class Linkedin extends Base
|
||||
{
|
||||
public const NAME = 'linkedin';
|
||||
|
||||
protected array $scopes = ['r_liteprofile', 'r_emailaddress'];
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://www.linkedin.com/oauth/v2/authorization');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return 'https://www.linkedin.com/oauth/v2/accessToken';
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return parent::getTokenFields($code) + [Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE];
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token, ?array $query = []): array
|
||||
{
|
||||
$basicProfile = $this->getBasicProfile($token);
|
||||
$emailAddress = $this->getEmailAddress($token);
|
||||
|
||||
return \array_merge($basicProfile, $emailAddress);
|
||||
}
|
||||
|
||||
protected function getBasicProfile(string $token): array
|
||||
{
|
||||
$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 $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
protected function getEmailAddress(string $token): array
|
||||
{
|
||||
$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 $this->fromJsonBody($response)['elements.0.handle~'] ?? [];
|
||||
}
|
||||
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
$preferredLocale = ($user['firstName.preferredLocale.language'] ?? null).'_'.($user['firstName.preferredLocale.country'] ?? null);
|
||||
$firstName = $user['firstName.localized.'.$preferredLocale] ?? null;
|
||||
$lastName = $user['lastName.localized.'.$preferredLocale] ?? null;
|
||||
$name = $firstName.' '.$lastName;
|
||||
|
||||
$images = $user['profilePicture.displayImage~.elements'] ?? [];
|
||||
$avatars = \array_filter($images, static fn ($image) => ($image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] ?? 0) === 100);
|
||||
$avatar = \array_shift($avatars);
|
||||
$originalAvatars = \array_filter($images, static fn ($image) => ($image['data']['com.linkedin.digitalmedia.mediaartifact.StillImage']['storageSize']['width'] ?? 0) === 800);
|
||||
$originalAvatar = \array_shift($originalAvatars);
|
||||
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_ID] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $name,
|
||||
Contracts\ABNF_NAME => $name,
|
||||
Contracts\ABNF_EMAIL => $user['emailAddress'] ?? null,
|
||||
Contracts\ABNF_AVATAR => $avatar['identifiers.0.identifier'] ?? null,
|
||||
'avatar_original' => $originalAvatar['identifiers.0.identifier'] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
253
vendor/overtrue/socialite/src/Providers/OpenWeWork.php
vendored
Normal file
253
vendor/overtrue/socialite/src/Providers/OpenWeWork.php
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Overtrue\Socialite\Exceptions\AuthorizeFailedException;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @link https://open.work.weixin.qq.com/api/doc/90001/90143/91120
|
||||
*/
|
||||
class OpenWeWork extends Base
|
||||
{
|
||||
public const NAME = 'open-wework';
|
||||
|
||||
protected bool $detailed = false;
|
||||
|
||||
protected bool $asQrcode = false;
|
||||
|
||||
protected string $userType = 'member';
|
||||
|
||||
protected string $lang = 'zh';
|
||||
|
||||
protected ?string $suiteTicket = null;
|
||||
|
||||
protected ?int $agentId = null;
|
||||
|
||||
protected ?string $suiteAccessToken = null;
|
||||
|
||||
protected string $baseUrl = 'https://qyapi.weixin.qq.com';
|
||||
|
||||
public function __construct(array $config)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
if ($this->getConfig()->has('base_url')) {
|
||||
$this->baseUrl = $this->getConfig()->get('base_url');
|
||||
}
|
||||
}
|
||||
|
||||
public function withAgentId(int $agentId): self
|
||||
{
|
||||
$this->agentId = $agentId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function detailed(): self
|
||||
{
|
||||
$this->detailed = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function asQrcode(): self
|
||||
{
|
||||
$this->asQrcode = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withUserType(string $userType): self
|
||||
{
|
||||
$this->userType = $userType;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withLang(string $lang): self
|
||||
{
|
||||
$this->lang = $lang;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws GuzzleException
|
||||
* @throws AuthorizeFailedException
|
||||
*/
|
||||
public function userFromCode(string $code): Contracts\UserInterface
|
||||
{
|
||||
$user = $this->getUser($this->getSuiteAccessToken(), $code);
|
||||
|
||||
if ($this->detailed) {
|
||||
$user = \array_merge($user, $this->getUserByTicket($user['user_ticket']));
|
||||
}
|
||||
|
||||
return $this->mapUserToObject($user)->setProvider($this)->setRaw($user);
|
||||
}
|
||||
|
||||
public function withSuiteTicket(string $suiteTicket): self
|
||||
{
|
||||
$this->suiteTicket = $suiteTicket;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withSuiteAccessToken(string $suiteAccessToken): self
|
||||
{
|
||||
$this->suiteAccessToken = $suiteAccessToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\InvalidArgumentException
|
||||
*/
|
||||
public function getAuthUrl(): string
|
||||
{
|
||||
$queries = \array_filter([
|
||||
'appid' => $this->getClientId(),
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
Contracts\RFC6749_ABNF_RESPONSE_TYPE => Contracts\RFC6749_ABNF_CODE,
|
||||
Contracts\RFC6749_ABNF_SCOPE => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
Contracts\RFC6749_ABNF_STATE => $this->state,
|
||||
'agentid' => $this->agentId,
|
||||
]);
|
||||
|
||||
if ($this->asQrcode) {
|
||||
$queries = array_filter([
|
||||
'appid' => $queries['appid'] ?? $this->getClientId(),
|
||||
'redirect_uri' => $queries['redirect_uri'] ?? $this->redirectUrl,
|
||||
'usertype' => $this->userType,
|
||||
'lang' => $this->lang,
|
||||
'state' => $this->state,
|
||||
]);
|
||||
|
||||
return \sprintf('https://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect?%s', http_build_query($queries));
|
||||
}
|
||||
|
||||
return \sprintf('https://open.weixin.qq.com/connect/oauth2/authorize?%s#wechat_redirect', \http_build_query($queries));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\MethodDoesNotSupportException
|
||||
*/
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
throw new Exceptions\MethodDoesNotSupportException('Open WeWork doesn\'t support access_token mode');
|
||||
}
|
||||
|
||||
protected function getSuiteAccessToken(): string
|
||||
{
|
||||
return $this->suiteAccessToken ?? $this->suiteAccessToken = $this->requestSuiteAccessToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException|GuzzleException
|
||||
*/
|
||||
protected function getUser(string $token, string $code): array
|
||||
{
|
||||
$responseInstance = $this->getHttpClient()->get(
|
||||
$this->baseUrl.'/cgi-bin/service/getuserinfo3rd',
|
||||
[
|
||||
'query' => \array_filter(
|
||||
[
|
||||
'suite_access_token' => $token,
|
||||
Contracts\RFC6749_ABNF_CODE => $code,
|
||||
]
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (($response['errcode'] ?? 1) > 0 || (empty($response['UserId']) && empty($response['openid']))) {
|
||||
throw new Exceptions\AuthorizeFailedException((string) $responseInstance->getBody(), $response);
|
||||
} elseif (empty($response['user_ticket'])) {
|
||||
$this->detailed = false;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
protected function getUserByTicket(string $userTicket): array
|
||||
{
|
||||
$responseInstance = $this->getHttpClient()->post(
|
||||
$this->baseUrl.'/cgi-bin/service/auth/getuserdetail3rd',
|
||||
[
|
||||
'query' => [
|
||||
'suite_access_token' => $this->getSuiteAccessToken(),
|
||||
],
|
||||
'json' => [
|
||||
'user_ticket' => $userTicket,
|
||||
],
|
||||
],
|
||||
);
|
||||
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (($response['errcode'] ?? 1) > 0 || empty($response['userid'])) {
|
||||
throw new Exceptions\AuthorizeFailedException((string) $responseInstance->getBody(), $response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User($this->detailed ? [
|
||||
Contracts\ABNF_ID => $user['userid'] ?? $user['UserId'] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user[Contracts\ABNF_AVATAR] ?? null,
|
||||
'gender' => $user['gender'] ?? null,
|
||||
'corpid' => $user['corpid'] ?? $user['CorpId'] ?? null,
|
||||
'open_userid' => $user['open_userid'] ?? null,
|
||||
'qr_code' => $user['qr_code'] ?? null,
|
||||
] : [
|
||||
Contracts\ABNF_ID => $user['userid'] ?? $user['UserId'] ?? $user['OpenId'] ?? $user['openid'] ?? null,
|
||||
'corpid' => $user['CorpId'] ?? null,
|
||||
'open_userid' => $user['open_userid'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
protected function requestSuiteAccessToken(): string
|
||||
{
|
||||
$responseInstance = $this->getHttpClient()->post(
|
||||
$this->baseUrl.'/cgi-bin/service/get_suite_token',
|
||||
[
|
||||
'json' => [
|
||||
'suite_id' => $this->config->get('suite_id') ?? $this->config->get('client_id'),
|
||||
'suite_secret' => $this->config->get('suite_secret') ?? $this->config->get('client_secret'),
|
||||
'suite_ticket' => $this->suiteTicket,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (isset($response['errcode']) && $response['errcode'] > 0) {
|
||||
throw new Exceptions\AuthorizeFailedException((string) $responseInstance->getBody(), $response);
|
||||
}
|
||||
|
||||
return $response['suite_access_token'];
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
65
vendor/overtrue/socialite/src/Providers/Outlook.php
vendored
Normal file
65
vendor/overtrue/socialite/src/Providers/Outlook.php
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
class Outlook extends Base
|
||||
{
|
||||
public const NAME = 'outlook';
|
||||
|
||||
protected array $scopes = ['User.Read'];
|
||||
|
||||
protected string $scopeSeparator = ' ';
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://login.microsoftonline.com/common/oauth2/v2.0/authorize');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token, ?array $query = []): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get(
|
||||
'https://graph.microsoft.com/v1.0/me',
|
||||
['headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_ID] ?? null,
|
||||
Contracts\ABNF_NICKNAME => null,
|
||||
Contracts\ABNF_NAME => $user['displayName'] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user['userPrincipalName'] ?? null,
|
||||
Contracts\ABNF_AVATAR => null,
|
||||
]);
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return parent::getTokenFields($code) + [Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE];
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
<?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',
|
||||
]);
|
||||
}
|
||||
}
|
||||
243
vendor/overtrue/socialite/src/Providers/QCloud.php
vendored
Normal file
243
vendor/overtrue/socialite/src/Providers/QCloud.php
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
class QCloud extends Base
|
||||
{
|
||||
public const NAME = 'qcloud';
|
||||
|
||||
protected array $scopes = ['login'];
|
||||
|
||||
protected string $accessTokenKey = 'UserAccessToken';
|
||||
|
||||
protected string $refreshTokenKey = 'UserRefreshToken';
|
||||
|
||||
protected string $expiresInKey = 'ExpiresAt';
|
||||
|
||||
protected ?string $openId;
|
||||
|
||||
protected ?string $unionId;
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase('https://cloud.tencent.com/open/authorize');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
protected function getAppId(): string
|
||||
{
|
||||
return $this->config->get(Contracts\ABNF_APP_ID) ?? $this->getClientId();
|
||||
}
|
||||
|
||||
protected function getSecretId(): string
|
||||
{
|
||||
return $this->config->get('secret_id');
|
||||
}
|
||||
|
||||
protected function getSecretKey(): string
|
||||
{
|
||||
return $this->config->get('secret_key');
|
||||
}
|
||||
|
||||
public function TokenFromCode(string $code): array
|
||||
{
|
||||
$response = $this->performRequest(
|
||||
'GET',
|
||||
'open.tencentcloudapi.com',
|
||||
'GetUserAccessToken',
|
||||
'2018-12-25',
|
||||
[
|
||||
'query' => [
|
||||
'UserAuthCode' => $code,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
return $this->parseAccessToken($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
*/
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$secret = $this->getFederationToken($token);
|
||||
|
||||
return $this->performRequest(
|
||||
'GET',
|
||||
'open.tencentcloudapi.com',
|
||||
'GetUserBaseInfo',
|
||||
'2018-12-25',
|
||||
[
|
||||
'headers' => [
|
||||
'X-TC-Token' => $secret['Token'],
|
||||
],
|
||||
],
|
||||
$secret['TmpSecretId'],
|
||||
$secret['TmpSecretKey'],
|
||||
);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $this->openId ?? null,
|
||||
Contracts\ABNF_NAME => $user['Nickname'] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user['Nickname'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
*/
|
||||
public function performRequest(string $method, string $host, string $action, string $version, array $options = [], ?string $secretId = null, ?string $secretKey = null): array
|
||||
{
|
||||
$method = \strtoupper($method);
|
||||
$timestamp = \time();
|
||||
$credential = \sprintf('%s/%s/tc3_request', \gmdate('Y-m-d', $timestamp), $this->getServiceFromHost($host));
|
||||
$options['headers'] = \array_merge(
|
||||
$options['headers'] ?? [],
|
||||
[
|
||||
'X-TC-Action' => $action,
|
||||
'X-TC-Timestamp' => $timestamp,
|
||||
'X-TC-Version' => $version,
|
||||
'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8',
|
||||
]
|
||||
);
|
||||
|
||||
$signature = $this->sign($method, $host, $options['query'] ?? [], '', $options['headers'], $credential, $secretKey);
|
||||
$options['headers']['Authorization'] =
|
||||
\sprintf(
|
||||
'TC3-HMAC-SHA256 Credential=%s/%s, SignedHeaders=content-type;host, Signature=%s',
|
||||
$secretId ?? $this->getSecretId(),
|
||||
$credential,
|
||||
$signature
|
||||
);
|
||||
$response = $this->getHttpClient()->get("https://{$host}/", $options);
|
||||
|
||||
$response = $this->fromJsonBody($response);
|
||||
|
||||
if (! empty($response['Response']['Error'])) {
|
||||
throw new Exceptions\AuthorizeFailedException(
|
||||
\sprintf('%s: %s', $response['Response']['Error']['Code'], $response['Response']['Error']['Message']),
|
||||
$response
|
||||
);
|
||||
}
|
||||
|
||||
return $response['Response'] ?? [];
|
||||
}
|
||||
|
||||
protected function sign(string $requestMethod, string $host, array $query, string $payload, array $headers, string $credential, ?string $secretKey = null): bool|string
|
||||
{
|
||||
$canonicalRequestString = \implode(
|
||||
"\n",
|
||||
[
|
||||
$requestMethod,
|
||||
'/',
|
||||
\http_build_query($query),
|
||||
"content-type:{$headers['Content-Type']}\nhost:{$host}\n",
|
||||
'content-type;host',
|
||||
\hash('SHA256', $payload),
|
||||
]
|
||||
);
|
||||
|
||||
$signString = \implode(
|
||||
"\n",
|
||||
[
|
||||
'TC3-HMAC-SHA256',
|
||||
$headers['X-TC-Timestamp'],
|
||||
$credential,
|
||||
\hash('SHA256', $canonicalRequestString),
|
||||
]
|
||||
);
|
||||
|
||||
$secretKey = $secretKey ?? $this->getSecretKey();
|
||||
$secretDate = \hash_hmac('SHA256', \gmdate('Y-m-d', $headers['X-TC-Timestamp']), "TC3{$secretKey}", true);
|
||||
$secretService = \hash_hmac('SHA256', $this->getServiceFromHost($host), $secretDate, true);
|
||||
$secretSigning = \hash_hmac('SHA256', 'tc3_request', $secretService, true);
|
||||
|
||||
return \hash_hmac('SHA256', $signString, $secretSigning);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
*/
|
||||
protected function parseAccessToken(array | string $body): array
|
||||
{
|
||||
if (! \is_array($body)) {
|
||||
$body = \json_decode($body, true);
|
||||
}
|
||||
|
||||
if (empty($body['UserOpenId'] ?? null)) {
|
||||
throw new Exceptions\AuthorizeFailedException('Authorize Failed: '.\json_encode($body, JSON_UNESCAPED_UNICODE), $body);
|
||||
}
|
||||
|
||||
$this->openId = $body['UserOpenId'] ?? null;
|
||||
$this->unionId = $body['UserUnionId'] ?? null;
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
*/
|
||||
protected function getFederationToken(string $accessToken): array
|
||||
{
|
||||
$response = $this->performRequest(
|
||||
'GET',
|
||||
'sts.tencentcloudapi.com',
|
||||
'GetThirdPartyFederationToken',
|
||||
'2018-08-13',
|
||||
[
|
||||
'query' => [
|
||||
'UserAccessToken' => $accessToken,
|
||||
'Duration' => 7200,
|
||||
'ApiAppId' => 0,
|
||||
],
|
||||
'headers' => [
|
||||
'X-TC-Region' => 'ap-guangzhou', // 官方人员说写死
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
if (empty($response['Credentials'] ?? null)) {
|
||||
throw new Exceptions\AuthorizeFailedException('Get Federation Token failed.', $response);
|
||||
}
|
||||
|
||||
return $response['Credentials'];
|
||||
}
|
||||
|
||||
protected function getCodeFields(): array
|
||||
{
|
||||
$fields = \array_merge(
|
||||
[
|
||||
Contracts\ABNF_APP_ID => $this->getAppId(),
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
Contracts\RFC6749_ABNF_SCOPE => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
Contracts\RFC6749_ABNF_RESPONSE_TYPE => Contracts\RFC6749_ABNF_CODE,
|
||||
],
|
||||
$this->parameters
|
||||
);
|
||||
|
||||
if ($this->state) {
|
||||
$fields[Contracts\RFC6749_ABNF_STATE] = $this->state;
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
protected function getServiceFromHost(string $host): string
|
||||
{
|
||||
return \explode('.', $host)[0] ?? '';
|
||||
}
|
||||
}
|
||||
100
vendor/overtrue/socialite/src/Providers/QQ.php
vendored
Normal file
100
vendor/overtrue/socialite/src/Providers/QQ.php
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see http://wiki.connect.qq.com/oauth2-0%E7%AE%80%E4%BB%8B [QQ - OAuth 2.0 登录QQ]
|
||||
*/
|
||||
class QQ extends Base
|
||||
{
|
||||
public const NAME = 'qq';
|
||||
|
||||
protected string $baseUrl = 'https://graph.qq.com';
|
||||
|
||||
protected array $scopes = ['get_user_info'];
|
||||
|
||||
protected bool $withUnionId = false;
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth2.0/authorize');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return $this->baseUrl.'/oauth2.0/token';
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return parent::getTokenFields($code) + [Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE];
|
||||
}
|
||||
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->getTokenUrl(), [
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
\parse_str((string) $response->getBody(), $token);
|
||||
|
||||
return $this->normalizeAccessTokenResponse($token);
|
||||
}
|
||||
|
||||
public function withUnionId(): self
|
||||
{
|
||||
$this->withUnionId = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/oauth2.0/me', [
|
||||
'query' => [
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $token,
|
||||
'fmt' => 'json',
|
||||
] + ($this->withUnionId ? ['unionid' => 1] : []),
|
||||
]);
|
||||
|
||||
$me = $this->fromJsonBody($response);
|
||||
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/user/get_user_info', [
|
||||
'query' => [
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $token,
|
||||
'fmt' => 'json',
|
||||
'openid' => $me['openid'],
|
||||
'oauth_consumer_key' => $this->getClientId(),
|
||||
],
|
||||
]);
|
||||
|
||||
return $this->fromJsonBody($response) + [
|
||||
'unionid' => $me['unionid'] ?? null,
|
||||
'openid' => $me['openid'] ?? null,
|
||||
];
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user['openid'] ?? null,
|
||||
Contracts\ABNF_NAME => $user['nickname'] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user['nickname'] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user['email'] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user['figureurl_qq_2'] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
144
vendor/overtrue/socialite/src/Providers/Taobao.php
vendored
Normal file
144
vendor/overtrue/socialite/src/Providers/Taobao.php
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see https://open.taobao.com/doc.htm?docId=102635&docType=1&source=search [Taobao - OAuth 2.0 授权登录]
|
||||
*/
|
||||
class Taobao extends Base
|
||||
{
|
||||
public const NAME = 'taobao';
|
||||
|
||||
protected string $baseUrl = 'https://oauth.taobao.com';
|
||||
|
||||
protected string $gatewayUrl = 'https://eco.taobao.com/router/rest';
|
||||
|
||||
protected string $view = 'web';
|
||||
|
||||
protected array $scopes = ['user_info'];
|
||||
|
||||
public function withView(string $view): self
|
||||
{
|
||||
$this->view = $view;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/authorize');
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
'view' => 'string',
|
||||
Contracts\RFC6749_ABNF_RESPONSE_TYPE => 'string',
|
||||
])]
|
||||
public function getCodeFields(): array
|
||||
{
|
||||
return [
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => $this->getClientId(),
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
'view' => $this->view,
|
||||
Contracts\RFC6749_ABNF_RESPONSE_TYPE => Contracts\RFC6749_ABNF_CODE,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return $this->baseUrl.'/token';
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
'view' => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return parent::getTokenFields($code) + [
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
'view' => $this->view,
|
||||
];
|
||||
}
|
||||
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->normalizeAccessTokenResponse($response->getBody());
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token, ?array $query = []): array
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getUserInfoUrl($this->gatewayUrl, $token));
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_OPEN_ID] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user['nick'] ?? null,
|
||||
Contracts\ABNF_NAME => $user['nick'] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user[Contracts\ABNF_AVATAR] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function generateSign(array $params): string
|
||||
{
|
||||
\ksort($params);
|
||||
|
||||
$stringToBeSigned = $this->getConfig()->get(Contracts\RFC6749_ABNF_CLIENT_SECRET);
|
||||
|
||||
foreach ($params as $k => $v) {
|
||||
if (! \is_array($v) && ! \str_starts_with($v, '@')) {
|
||||
$stringToBeSigned .= "$k$v";
|
||||
}
|
||||
}
|
||||
|
||||
$stringToBeSigned .= $this->getConfig()->get(Contracts\RFC6749_ABNF_CLIENT_SECRET);
|
||||
|
||||
return \strtoupper(\md5($stringToBeSigned));
|
||||
}
|
||||
|
||||
protected function getPublicFields(string $token, array $apiFields = []): array
|
||||
{
|
||||
$fields = [
|
||||
'app_key' => $this->getClientId(),
|
||||
'sign_method' => 'md5',
|
||||
'session' => $token,
|
||||
'timestamp' => (new \DateTime('now', new \DateTimeZone('Asia/Shanghai')))->format('Y-m-d H:i:s'),
|
||||
'v' => '2.0',
|
||||
'format' => 'json',
|
||||
];
|
||||
|
||||
$fields = \array_merge($apiFields, $fields);
|
||||
$fields['sign'] = $this->generateSign($fields);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
protected function getUserInfoUrl(string $url, string $token): string
|
||||
{
|
||||
$apiFields = ['method' => 'taobao.miniapp.userInfo.get'];
|
||||
|
||||
$query = \http_build_query($this->getPublicFields($token, $apiFields), '', '&', $this->encodingType);
|
||||
|
||||
return $url.'?'.$query;
|
||||
}
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
147
vendor/overtrue/socialite/src/Providers/Tapd.php
vendored
Normal file
147
vendor/overtrue/socialite/src/Providers/Tapd.php
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Overtrue\Socialite\User;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* @see https://www.tapd.cn/help/show#1120003271001000708
|
||||
*/
|
||||
class Tapd extends Base
|
||||
{
|
||||
public const NAME = 'tapd';
|
||||
|
||||
protected string $baseUrl = 'https://api.tapd.cn';
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/quickstart/testauth');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return $this->baseUrl.'/tokens/request_token';
|
||||
}
|
||||
|
||||
protected function getRefreshTokenUrl(): string
|
||||
{
|
||||
return $this->baseUrl.'/tokens/refresh_token';
|
||||
}
|
||||
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Basic '.\base64_encode(\sprintf('%s:%s', $this->getClientId(), $this->getClientSecret())),
|
||||
],
|
||||
'form_params' => $this->getTokenFields($code),
|
||||
]);
|
||||
|
||||
return $this->normalizeAccessTokenResponse($response->getBody());
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return [
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
Contracts\RFC6749_ABNF_CODE => $code,
|
||||
];
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_REFRESH_TOKEN => 'string',
|
||||
])]
|
||||
protected function getRefreshTokenFields(string $refreshToken): array
|
||||
{
|
||||
return [
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_REFRESH_TOKEN,
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
Contracts\RFC6749_ABNF_REFRESH_TOKEN => $refreshToken,
|
||||
];
|
||||
}
|
||||
|
||||
public function tokenFromRefreshToken(string $refreshToken): array
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->getRefreshTokenUrl(), [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Basic '.\base64_encode(\sprintf('%s:%s', $this->getClientId(), $this->getClientSecret())),
|
||||
],
|
||||
'form_params' => $this->getRefreshTokenFields($refreshToken),
|
||||
]);
|
||||
|
||||
return $this->normalizeAccessTokenResponse((string) $response->getBody());
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/users/info', [
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$token,
|
||||
],
|
||||
]);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\BadRequestException
|
||||
*/
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
if (! isset($user['status']) && $user['status'] != 1) {
|
||||
throw new Exceptions\BadRequestException('用户信息获取失败');
|
||||
}
|
||||
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user['data'][Contracts\ABNF_ID] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user['data']['nick'] ?? null,
|
||||
Contracts\ABNF_NAME => $user['data'][Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user['data'][Contracts\ABNF_EMAIL] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user['data'][Contracts\ABNF_AVATAR] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
*/
|
||||
protected function normalizeAccessTokenResponse(mixed $response): array
|
||||
{
|
||||
if ($response instanceof StreamInterface) {
|
||||
$response->rewind();
|
||||
$response = (string) $response;
|
||||
}
|
||||
|
||||
if (\is_string($response)) {
|
||||
$response = \json_decode($response, true) ?? [];
|
||||
}
|
||||
|
||||
if (! \is_array($response)) {
|
||||
throw new Exceptions\AuthorizeFailedException('Invalid token response', [$response]);
|
||||
}
|
||||
|
||||
if (empty($response['data'][$this->accessTokenKey] ?? null)) {
|
||||
throw new Exceptions\AuthorizeFailedException('Authorize Failed: '.\json_encode($response, JSON_UNESCAPED_UNICODE), $response);
|
||||
}
|
||||
|
||||
return $response + [
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $response['data'][$this->accessTokenKey],
|
||||
Contracts\RFC6749_ABNF_REFRESH_TOKEN => $response['data'][$this->refreshTokenKey] ?? null,
|
||||
Contracts\RFC6749_ABNF_EXPIRES_IN => \intval($response['data'][$this->expiresInKey] ?? 0),
|
||||
];
|
||||
}
|
||||
}
|
||||
33
vendor/overtrue/socialite/src/Providers/TouTiao.php
vendored
Normal file
33
vendor/overtrue/socialite/src/Providers/TouTiao.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see https://open.douyin.com/platform/resource/docs/openapi/account-permission/toutiao-get-permission-code
|
||||
*/
|
||||
class TouTiao extends DouYin
|
||||
{
|
||||
public const NAME = 'toutiao';
|
||||
|
||||
protected string $baseUrl = 'https://open.snssdk.com';
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth/authorize/');
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_OPEN_ID] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NICKNAME] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user[Contracts\ABNF_NICKNAME] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user[Contracts\ABNF_AVATAR] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
218
vendor/overtrue/socialite/src/Providers/WeChat.php
vendored
Normal file
218
vendor/overtrue/socialite/src/Providers/WeChat.php
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Overtrue\Socialite\User;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @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 WeChat extends Base
|
||||
{
|
||||
public const NAME = 'wechat';
|
||||
|
||||
protected string $baseUrl = 'https://api.weixin.qq.com/sns';
|
||||
|
||||
protected array $scopes = ['snsapi_login'];
|
||||
|
||||
protected bool $withCountryCode = false;
|
||||
|
||||
protected ?array $component = null;
|
||||
|
||||
protected ?string $openid = null;
|
||||
|
||||
public function __construct(array $config)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
if ($this->getConfig()->has('component')) {
|
||||
$this->prepareForComponent((array) $this->getConfig()->get('component'));
|
||||
}
|
||||
}
|
||||
|
||||
public function withOpenid(string $openid): self
|
||||
{
|
||||
$this->openid = $openid;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withCountryCode(): self
|
||||
{
|
||||
$this->withCountryCode = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function tokenFromCode(string $code): array
|
||||
{
|
||||
$response = $this->getTokenFromCode($code);
|
||||
|
||||
return $this->normalizeAccessTokenResponse($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string> $componentConfig [Contracts\ABNF_ID => xxx, Contracts\ABNF_TOKEN => xxx]
|
||||
*/
|
||||
public function withComponent(array $componentConfig): self
|
||||
{
|
||||
$this->prepareForComponent($componentConfig);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getComponent(): ?array
|
||||
{
|
||||
return $this->component;
|
||||
}
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
$path = 'oauth2/authorize';
|
||||
|
||||
if (\in_array('snsapi_login', $this->scopes)) {
|
||||
$path = 'qrconnect';
|
||||
}
|
||||
|
||||
return $this->buildAuthUrlFromBase("https://open.weixin.qq.com/connect/{$path}");
|
||||
}
|
||||
|
||||
protected function buildAuthUrlFromBase(string $url): string
|
||||
{
|
||||
$query = \http_build_query($this->getCodeFields(), '', '&', $this->encodingType);
|
||||
|
||||
return $url.'?'.$query.'#wechat_redirect';
|
||||
}
|
||||
|
||||
protected function getCodeFields(): array
|
||||
{
|
||||
if (! empty($this->component)) {
|
||||
$this->with(\array_merge($this->parameters, ['component_appid' => $this->component[Contracts\ABNF_ID]]));
|
||||
}
|
||||
|
||||
return \array_merge([
|
||||
'appid' => $this->getClientId(),
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
Contracts\RFC6749_ABNF_RESPONSE_TYPE => Contracts\RFC6749_ABNF_CODE,
|
||||
Contracts\RFC6749_ABNF_SCOPE => $this->formatScopes($this->scopes, $this->scopeSeparator),
|
||||
Contracts\RFC6749_ABNF_STATE => $this->state ?: \md5(\uniqid(Contracts\RFC6749_ABNF_STATE, true)),
|
||||
'connect_redirect' => 1,
|
||||
], $this->parameters);
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return \sprintf($this->baseUrl.'/oauth2%s/access_token', empty($this->component) ? '' : '/component');
|
||||
}
|
||||
|
||||
public function userFromCode(string $code): Contracts\UserInterface
|
||||
{
|
||||
if (\in_array('snsapi_base', $this->scopes)) {
|
||||
return $this->mapUserToObject($this->fromJsonBody($this->getTokenFromCode($code)));
|
||||
}
|
||||
|
||||
$token = $this->tokenFromCode($code);
|
||||
|
||||
$this->withOpenid($token['openid']);
|
||||
|
||||
$user = $this->userFromToken($token[$this->accessTokenKey]);
|
||||
|
||||
return $user->setRefreshToken($token[Contracts\RFC6749_ABNF_REFRESH_TOKEN])
|
||||
->setExpiresIn($token[Contracts\RFC6749_ABNF_EXPIRES_IN])
|
||||
->setTokenResponse($token);
|
||||
}
|
||||
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$language = $this->withCountryCode ? null : (isset($this->parameters['lang']) ? $this->parameters['lang'] : 'zh_CN');
|
||||
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/userinfo', [
|
||||
'query' => \array_filter([
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $token,
|
||||
'openid' => $this->openid,
|
||||
'lang' => $language,
|
||||
]),
|
||||
]);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user['openid'] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NICKNAME] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user[Contracts\ABNF_NICKNAME] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user['headimgurl'] ?? null,
|
||||
Contracts\ABNF_EMAIL => null,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return empty($this->component) ? [
|
||||
'appid' => $this->getClientId(),
|
||||
'secret' => $this->getClientSecret(),
|
||||
Contracts\RFC6749_ABNF_CODE => $code,
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
] : [
|
||||
'appid' => $this->getClientId(),
|
||||
'component_appid' => $this->component[Contracts\ABNF_ID],
|
||||
'component_access_token' => $this->component[Contracts\ABNF_TOKEN],
|
||||
Contracts\RFC6749_ABNF_CODE => $code,
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getTokenFromCode(string $code): ResponseInterface
|
||||
{
|
||||
return $this->getHttpClient()->get($this->getTokenUrl(), [
|
||||
'headers' => ['Accept' => 'application/json'],
|
||||
'query' => $this->getTokenFields($code),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\InvalidArgumentException
|
||||
*/
|
||||
protected function prepareForComponent(array $component): void
|
||||
{
|
||||
$config = [];
|
||||
foreach ($component as $key => $value) {
|
||||
if (\is_callable($value)) {
|
||||
$value = \call_user_func($value, $this);
|
||||
}
|
||||
|
||||
switch ($key) {
|
||||
case Contracts\ABNF_ID:
|
||||
case Contracts\ABNF_APP_ID:
|
||||
case 'component_app_id':
|
||||
$config[Contracts\ABNF_ID] = $value;
|
||||
break;
|
||||
case Contracts\ABNF_TOKEN:
|
||||
case Contracts\RFC6749_ABNF_ACCESS_TOKEN:
|
||||
case 'app_token':
|
||||
case 'component_access_token':
|
||||
$config[Contracts\ABNF_TOKEN] = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (2 !== \count($config)) {
|
||||
throw new Exceptions\InvalidArgumentException('Please check your config arguments were available.');
|
||||
}
|
||||
|
||||
if (1 === \count($this->scopes) && \in_array('snsapi_login', $this->scopes)) {
|
||||
$this->scopes = ['snsapi_base'];
|
||||
}
|
||||
|
||||
$this->component = $config;
|
||||
}
|
||||
}
|
||||
@@ -1,234 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
213
vendor/overtrue/socialite/src/Providers/WeWork.php
vendored
Normal file
213
vendor/overtrue/socialite/src/Providers/WeWork.php
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @link https://developer.work.weixin.qq.com/document/path/91022
|
||||
*/
|
||||
class WeWork extends Base
|
||||
{
|
||||
public const NAME = 'wework';
|
||||
|
||||
protected bool $detailed = false;
|
||||
|
||||
protected ?int $agentId = null;
|
||||
|
||||
protected ?string $apiAccessToken;
|
||||
|
||||
protected bool $asQrcode = false;
|
||||
|
||||
protected string $baseUrl = 'https://qyapi.weixin.qq.com';
|
||||
|
||||
public function __construct(array $config)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
if ($this->getConfig()->has('base_url')) {
|
||||
$this->baseUrl = $this->getConfig()->get('base_url');
|
||||
}
|
||||
|
||||
if ($this->getConfig()->has('agent_id')) {
|
||||
$this->agentId = $this->getConfig()->get('agent_id');
|
||||
}
|
||||
}
|
||||
|
||||
public function getBaseUrl(): ?string
|
||||
{
|
||||
return $this->baseUrl;
|
||||
}
|
||||
|
||||
public function userFromCode(string $code): Contracts\UserInterface
|
||||
{
|
||||
$token = $this->getApiAccessToken();
|
||||
$user = $this->getUser($token, $code);
|
||||
|
||||
if ($this->detailed) {
|
||||
$user = $this->getUserById($user['UserId']);
|
||||
}
|
||||
|
||||
return $this->mapUserToObject($user)->setProvider($this)->setRaw($user);
|
||||
}
|
||||
|
||||
public function withAgentId(int $agentId): self
|
||||
{
|
||||
$this->agentId = $agentId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function detailed(): self
|
||||
{
|
||||
$this->detailed = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function asQrcode(): self
|
||||
{
|
||||
$this->asQrcode = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withApiAccessToken(string $apiAccessToken): self
|
||||
{
|
||||
$this->apiAccessToken = $apiAccessToken;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAuthUrl(): string
|
||||
{
|
||||
$scopes = $this->formatScopes($this->scopes, $this->scopeSeparator);
|
||||
$queries = array_filter([
|
||||
'appid' => $this->getClientId(),
|
||||
'agentid' => $this->agentId,
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
|
||||
Contracts\RFC6749_ABNF_RESPONSE_TYPE => Contracts\RFC6749_ABNF_CODE,
|
||||
Contracts\RFC6749_ABNF_SCOPE => $scopes,
|
||||
Contracts\RFC6749_ABNF_STATE => $this->state,
|
||||
]);
|
||||
|
||||
if (! $this->agentId && (str_contains($scopes, 'snsapi_privateinfo') || $this->asQrcode)) {
|
||||
throw new Exceptions\InvalidArgumentException("agent_id is require when qrcode mode or scopes is 'snsapi_privateinfo'");
|
||||
}
|
||||
|
||||
if ($this->asQrcode) {
|
||||
unset($queries[Contracts\RFC6749_ABNF_SCOPE]);
|
||||
|
||||
return \sprintf('https://open.work.weixin.qq.com/wwopen/sso/qrConnect?%s', http_build_query($queries));
|
||||
}
|
||||
|
||||
return \sprintf('https://open.weixin.qq.com/connect/oauth2/authorize?%s#wechat_redirect', \http_build_query($queries));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\MethodDoesNotSupportException
|
||||
*/
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
throw new Exceptions\MethodDoesNotSupportException('WeWork doesn\'t support access_token mode');
|
||||
}
|
||||
|
||||
protected function getApiAccessToken(): string
|
||||
{
|
||||
return $this->apiAccessToken ?? $this->apiAccessToken = $this->requestApiAccessToken();
|
||||
}
|
||||
|
||||
protected function getUser(string $token, string $code): array
|
||||
{
|
||||
$responseInstance = $this->getHttpClient()->get(
|
||||
$this->baseUrl.'/cgi-bin/user/getuserinfo',
|
||||
[
|
||||
'query' => \array_filter(
|
||||
[
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $token,
|
||||
Contracts\RFC6749_ABNF_CODE => $code,
|
||||
]
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (($response['errcode'] ?? 1) > 0 || (empty($response['UserId']) && empty($response['OpenId']))) {
|
||||
throw new Exceptions\AuthorizeFailedException((string) $responseInstance->getBody(), $response);
|
||||
} elseif (empty($response['UserId'])) {
|
||||
$this->detailed = false;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
*/
|
||||
protected function getUserById(string $userId): array
|
||||
{
|
||||
$responseInstance = $this->getHttpClient()->post($this->baseUrl.'/cgi-bin/user/get', [
|
||||
'query' => [
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $this->getApiAccessToken(),
|
||||
'userid' => $userId,
|
||||
],
|
||||
]);
|
||||
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (($response['errcode'] ?? 1) > 0 || empty($response['userid'])) {
|
||||
throw new Exceptions\AuthorizeFailedException((string) $responseInstance->getBody(), $response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User($this->detailed ? [
|
||||
Contracts\ABNF_ID => $user['userid'] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user[Contracts\ABNF_AVATAR] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
] : [
|
||||
Contracts\ABNF_ID => $user['UserId'] ?? null ?: $user['OpenId'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\AuthorizeFailedException
|
||||
*/
|
||||
protected function requestApiAccessToken(): string
|
||||
{
|
||||
$responseInstance = $this->getHttpClient()->get($this->baseUrl.'/cgi-bin/gettoken', [
|
||||
'query' => \array_filter(
|
||||
[
|
||||
'corpid' => $this->config->get('corp_id')
|
||||
?? $this->config->get('corpid')
|
||||
?? $this->config->get(Contracts\RFC6749_ABNF_CLIENT_ID),
|
||||
'corpsecret' => $this->config->get('corp_secret')
|
||||
?? $this->config->get('corpsecret')
|
||||
?? $this->config->get(Contracts\RFC6749_ABNF_CLIENT_SECRET),
|
||||
]
|
||||
),
|
||||
]);
|
||||
|
||||
$response = $this->fromJsonBody($responseInstance);
|
||||
|
||||
if (($response['errcode'] ?? 1) > 0) {
|
||||
throw new Exceptions\AuthorizeFailedException((string) $responseInstance->getBody(), $response);
|
||||
}
|
||||
|
||||
return $response[Contracts\RFC6749_ABNF_ACCESS_TOKEN];
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
<?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'),
|
||||
]));
|
||||
}
|
||||
}
|
||||
104
vendor/overtrue/socialite/src/Providers/Weibo.php
vendored
Normal file
104
vendor/overtrue/socialite/src/Providers/Weibo.php
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\ArrayShape;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @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 Weibo extends Base
|
||||
{
|
||||
public const NAME = 'weibo';
|
||||
|
||||
protected string $baseUrl = 'https://api.weibo.com';
|
||||
|
||||
protected array $scopes = [Contracts\ABNF_EMAIL];
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth2/authorize');
|
||||
}
|
||||
|
||||
protected function getTokenUrl(): string
|
||||
{
|
||||
return $this->baseUrl.'/2/oauth2/access_token';
|
||||
}
|
||||
|
||||
#[ArrayShape([
|
||||
Contracts\RFC6749_ABNF_CLIENT_ID => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CLIENT_SECRET => 'null|string',
|
||||
Contracts\RFC6749_ABNF_CODE => 'string',
|
||||
Contracts\RFC6749_ABNF_REDIRECT_URI => 'null|string',
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => 'string',
|
||||
])]
|
||||
protected function getTokenFields(string $code): array
|
||||
{
|
||||
return parent::getTokenFields($code) + [
|
||||
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\InvalidTokenException
|
||||
*/
|
||||
protected function getUserByToken(string $token): array
|
||||
{
|
||||
$uid = $this->getTokenPayload($token)['uid'] ?? null;
|
||||
|
||||
if (empty($uid)) {
|
||||
throw new Exceptions\InvalidTokenException('Invalid token.', $token);
|
||||
}
|
||||
|
||||
$response = $this->getHttpClient()->get($this->baseUrl.'/2/users/show.json', [
|
||||
'query' => [
|
||||
'uid' => $uid,
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $token,
|
||||
],
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
return $this->fromJsonBody($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exceptions\InvalidTokenException
|
||||
*/
|
||||
protected function getTokenPayload(string $token): array
|
||||
{
|
||||
$response = $this->getHttpClient()->post($this->baseUrl.'/oauth2/get_token_info', [
|
||||
'query' => [
|
||||
Contracts\RFC6749_ABNF_ACCESS_TOKEN => $token,
|
||||
],
|
||||
'headers' => [
|
||||
'Accept' => 'application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
$response = $this->fromJsonBody($response);
|
||||
|
||||
if (empty($response['uid'] ?? null)) {
|
||||
throw new Exceptions\InvalidTokenException(\sprintf('Invalid token %s', $token), $token);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_ID] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user['screen_name'] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NAME] ?? null,
|
||||
Contracts\ABNF_EMAIL => $user[Contracts\ABNF_EMAIL] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user['avatar_large'] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
<?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'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
33
vendor/overtrue/socialite/src/Providers/XiGua.php
vendored
Normal file
33
vendor/overtrue/socialite/src/Providers/XiGua.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Providers;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Contracts;
|
||||
use Overtrue\Socialite\User;
|
||||
|
||||
/**
|
||||
* @see https://open.douyin.com/platform/resource/docs/openapi/account-permission/xigua-get-permission-code
|
||||
*/
|
||||
class XiGua extends DouYin
|
||||
{
|
||||
public const NAME = 'xigua';
|
||||
|
||||
protected string $baseUrl = 'https://open-api.ixigua.com';
|
||||
|
||||
protected function getAuthUrl(): string
|
||||
{
|
||||
return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth/connect');
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
protected function mapUserToObject(array $user): Contracts\UserInterface
|
||||
{
|
||||
return new User([
|
||||
Contracts\ABNF_ID => $user[Contracts\ABNF_OPEN_ID] ?? null,
|
||||
Contracts\ABNF_NAME => $user[Contracts\ABNF_NICKNAME] ?? null,
|
||||
Contracts\ABNF_NICKNAME => $user[Contracts\ABNF_NICKNAME] ?? null,
|
||||
Contracts\ABNF_AVATAR => $user[Contracts\ABNF_AVATAR] ?? null,
|
||||
]);
|
||||
}
|
||||
}
|
||||
266
vendor/overtrue/socialite/src/SocialiteManager.php
vendored
266
vendor/overtrue/socialite/src/SocialiteManager.php
vendored
@@ -1,251 +1,117 @@
|
||||
<?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;
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
|
||||
/**
|
||||
* Class SocialiteManager.
|
||||
*/
|
||||
class SocialiteManager implements FactoryInterface
|
||||
class SocialiteManager implements Contracts\FactoryInterface
|
||||
{
|
||||
/**
|
||||
* The configuration.
|
||||
*
|
||||
* @var \Overtrue\Socialite\Config
|
||||
*/
|
||||
protected $config;
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* The request instance.
|
||||
*
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
protected array $resolved = [];
|
||||
|
||||
/**
|
||||
* The registered custom driver creators.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $customCreators = [];
|
||||
protected static array $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',
|
||||
protected const PROVIDERS = [
|
||||
Providers\Alipay::NAME => Providers\Alipay::class,
|
||||
Providers\Azure::NAME => Providers\Azure::class,
|
||||
Providers\Coding::NAME => Providers\Coding::class,
|
||||
Providers\DingTalk::NAME => Providers\DingTalk::class,
|
||||
Providers\DouYin::NAME => Providers\DouYin::class,
|
||||
Providers\Douban::NAME => Providers\Douban::class,
|
||||
Providers\Facebook::NAME => Providers\Facebook::class,
|
||||
Providers\FeiShu::NAME => Providers\FeiShu::class,
|
||||
Providers\Figma::NAME => Providers\Figma::class,
|
||||
Providers\GitHub::NAME => Providers\GitHub::class,
|
||||
Providers\Gitee::NAME => Providers\Gitee::class,
|
||||
Providers\Google::NAME => Providers\Google::class,
|
||||
Providers\Line::NAME => Providers\Line::class,
|
||||
Providers\Linkedin::NAME => Providers\Linkedin::class,
|
||||
Providers\OpenWeWork::NAME => Providers\OpenWeWork::class,
|
||||
Providers\Outlook::NAME => Providers\Outlook::class,
|
||||
Providers\QCloud::NAME => Providers\QCloud::class,
|
||||
Providers\QQ::NAME => Providers\QQ::class,
|
||||
Providers\Taobao::NAME => Providers\Taobao::class,
|
||||
Providers\Tapd::NAME => Providers\Tapd::class,
|
||||
Providers\TouTiao::NAME => Providers\TouTiao::class,
|
||||
Providers\WeChat::NAME => Providers\WeChat::class,
|
||||
Providers\WeWork::NAME => Providers\WeWork::class,
|
||||
Providers\Weibo::NAME => Providers\Weibo::class,
|
||||
Providers\XiGua::NAME => Providers\XiGua::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* 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)
|
||||
#[Pure]
|
||||
public function __construct(array $config)
|
||||
{
|
||||
$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)
|
||||
public function config(Config $config): self
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a driver instance.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
public function driver($driver)
|
||||
public function create(string $name): Contracts\ProviderInterface
|
||||
{
|
||||
$driver = strtolower($driver);
|
||||
$name = \strtolower($name);
|
||||
|
||||
if (!isset($this->drivers[$driver])) {
|
||||
$this->drivers[$driver] = $this->createDriver($driver);
|
||||
if (! isset($this->resolved[$name])) {
|
||||
$this->resolved[$name] = $this->createProvider($name);
|
||||
}
|
||||
|
||||
return $this->drivers[$driver];
|
||||
return $this->resolved[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\HttpFoundation\Request $request
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setRequest(Request $request)
|
||||
public function extend(string $name, Closure $callback): self
|
||||
{
|
||||
$this->request = $request;
|
||||
self::$customCreators[\strtolower($name)] = $callback;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\HttpFoundation\Request
|
||||
*/
|
||||
public function getRequest()
|
||||
public function getResolvedProviders(): array
|
||||
{
|
||||
return $this->request ?: $this->createDefaultRequest();
|
||||
return $this->resolved;
|
||||
}
|
||||
|
||||
public function buildProvider(string $provider, array $config): Contracts\ProviderInterface
|
||||
{
|
||||
$instance = new $provider($config);
|
||||
|
||||
$instance instanceof Contracts\ProviderInterface || throw new Exceptions\InvalidArgumentException("The {$provider} must be instanceof ProviderInterface.");
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new driver instance.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return ProviderInterface
|
||||
* @throws Exceptions\InvalidArgumentException
|
||||
*/
|
||||
protected function createDriver($driver)
|
||||
protected function createProvider(string $name): Contracts\ProviderInterface
|
||||
{
|
||||
if (isset($this->customCreators[$driver])) {
|
||||
return $this->callCustomCreator($driver);
|
||||
$config = $this->config->get($name, []);
|
||||
$provider = $config['provider'] ?? $name;
|
||||
|
||||
if (isset(self::$customCreators[$provider])) {
|
||||
return $this->callCustomCreator($provider, $config);
|
||||
}
|
||||
|
||||
if (isset($this->initialDrivers[$driver])) {
|
||||
$provider = $this->initialDrivers[$driver];
|
||||
$provider = __NAMESPACE__.'\\Providers\\'.$provider.'Provider';
|
||||
|
||||
return $this->buildProvider($provider, $this->formatConfig($this->config->get($driver)));
|
||||
if (! $this->isValidProvider($provider)) {
|
||||
throw new Exceptions\InvalidArgumentException("Provider [{$name}] not supported.");
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("Driver [$driver] not supported.");
|
||||
return $this->buildProvider(self::PROVIDERS[$provider] ?? $provider, $config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a custom driver creator.
|
||||
*
|
||||
* @param string $driver
|
||||
*
|
||||
* @return ProviderInterface
|
||||
*/
|
||||
protected function callCustomCreator($driver)
|
||||
protected function callCustomCreator(string $name, array $config): Contracts\ProviderInterface
|
||||
{
|
||||
return $this->customCreators[$driver]($this->config);
|
||||
return self::$customCreators[$name]($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create default request instance.
|
||||
*
|
||||
* @return Request
|
||||
*/
|
||||
protected function createDefaultRequest()
|
||||
protected function isValidProvider(string $provider): bool
|
||||
{
|
||||
$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);
|
||||
return isset(self::PROVIDERS[$provider]) || \is_subclass_of($provider, Contracts\ProviderInterface::class);
|
||||
}
|
||||
}
|
||||
|
||||
75
vendor/overtrue/socialite/src/Traits/HasAttributes.php
vendored
Normal file
75
vendor/overtrue/socialite/src/Traits/HasAttributes.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Overtrue\Socialite\Traits;
|
||||
|
||||
use JetBrains\PhpStorm\Pure;
|
||||
use Overtrue\Socialite\Exceptions;
|
||||
|
||||
trait HasAttributes
|
||||
{
|
||||
protected array $attributes = [];
|
||||
|
||||
public function getAttributes(): array
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
public function getAttribute(string $name, mixed $default = null): mixed
|
||||
{
|
||||
return $this->attributes[$name] ?? $default;
|
||||
}
|
||||
|
||||
public function setAttribute(string $name, mixed $value): self
|
||||
{
|
||||
$this->attributes[$name] = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function merge(array $attributes): self
|
||||
{
|
||||
$this->attributes = \array_merge($this->attributes, $attributes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
return \array_key_exists($offset, $this->attributes);
|
||||
}
|
||||
|
||||
public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
return $this->getAttribute($offset);
|
||||
}
|
||||
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
$this->setAttribute($offset, $value);
|
||||
}
|
||||
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
unset($this->attributes[$offset]);
|
||||
}
|
||||
|
||||
public function __get(string $property): mixed
|
||||
{
|
||||
return $this->getAttribute($property);
|
||||
}
|
||||
|
||||
#[Pure]
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->getAttributes();
|
||||
}
|
||||
|
||||
public function toJSON(): string
|
||||
{
|
||||
$result = \json_encode($this->getAttributes(), JSON_UNESCAPED_UNICODE);
|
||||
|
||||
false === $result && throw new Exceptions\Exception('Cannot Processing this instance as JSON stringify.');
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
206
vendor/overtrue/socialite/src/User.php
vendored
206
vendor/overtrue/socialite/src/User.php
vendored
@@ -1,204 +1,128 @@
|
||||
<?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
|
||||
class User implements ArrayAccess, Contracts\UserInterface, JsonSerializable
|
||||
{
|
||||
use HasAttributes;
|
||||
use Traits\HasAttributes;
|
||||
|
||||
/**
|
||||
* User constructor.
|
||||
*
|
||||
* @param array $attributes
|
||||
*/
|
||||
public function __construct(array $attributes)
|
||||
public function __construct(array $attributes, protected ?Contracts\ProviderInterface $provider = null)
|
||||
{
|
||||
$this->attributes = $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unique identifier for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
public function getId(): mixed
|
||||
{
|
||||
return $this->getAttribute('id');
|
||||
return $this->getAttribute(Contracts\ABNF_ID) ?? $this->getEmail();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the username for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUsername()
|
||||
public function getNickname(): ?string
|
||||
{
|
||||
return $this->getAttribute('username', $this->getId());
|
||||
return $this->getAttribute(Contracts\ABNF_NICKNAME) ?? $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the nickname / username for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNickname()
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->getAttribute('nickname');
|
||||
return $this->getAttribute(Contracts\ABNF_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full name of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
public function getEmail(): ?string
|
||||
{
|
||||
return $this->getAttribute('name');
|
||||
return $this->getAttribute(Contracts\ABNF_EMAIL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the e-mail address of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEmail()
|
||||
public function getAvatar(): ?string
|
||||
{
|
||||
return $this->getAttribute('email');
|
||||
return $this->getAttribute(Contracts\ABNF_AVATAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the avatar / image URL for the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAvatar()
|
||||
public function setAccessToken(string $value): self
|
||||
{
|
||||
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());
|
||||
}
|
||||
$this->setAttribute(Contracts\RFC6749_ABNF_ACCESS_TOKEN, $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $provider
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setProviderName($provider)
|
||||
public function getAccessToken(): ?string
|
||||
{
|
||||
$this->setAttribute('provider', $provider);
|
||||
return $this->getAttribute(Contracts\RFC6749_ABNF_ACCESS_TOKEN);
|
||||
}
|
||||
|
||||
public function setRefreshToken(?string $value): self
|
||||
{
|
||||
$this->setAttribute(Contracts\RFC6749_ABNF_REFRESH_TOKEN, $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getProviderName()
|
||||
public function getRefreshToken(): ?string
|
||||
{
|
||||
return $this->getAttribute('provider');
|
||||
return $this->getAttribute(Contracts\RFC6749_ABNF_REFRESH_TOKEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authorized token.
|
||||
*
|
||||
* @return \Overtrue\Socialite\AccessToken
|
||||
*/
|
||||
public function getToken()
|
||||
public function setExpiresIn(int $value): self
|
||||
{
|
||||
return new AccessToken([
|
||||
'access_token' => $this->getAccessToken(),
|
||||
'refresh_token' => $this->getAttribute('refresh_token')
|
||||
]);
|
||||
$this->setAttribute(Contracts\RFC6749_ABNF_EXPIRES_IN, $value);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user access token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccessToken()
|
||||
public function getExpiresIn(): ?int
|
||||
{
|
||||
return $this->getAttribute('token') ?: $this->getAttribute('access_token');
|
||||
return $this->getAttribute(Contracts\RFC6749_ABNF_EXPIRES_IN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user refresh token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRefreshToken()
|
||||
public function setRaw(array $user): self
|
||||
{
|
||||
return $this->getAttribute('refresh_token');
|
||||
$this->setAttribute('raw', $user);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original attributes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOriginal()
|
||||
public function getRaw(): array
|
||||
{
|
||||
return $this->getAttribute('original');
|
||||
return $this->getAttribute('raw');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function jsonSerialize()
|
||||
public function setTokenResponse(array $response): self
|
||||
{
|
||||
$this->setAttribute('token_response', $response);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTokenResponse(): mixed
|
||||
{
|
||||
return $this->getAttribute('token_response');
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
public function __serialize(): array
|
||||
{
|
||||
return serialize($this->attributes);
|
||||
return $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)
|
||||
public function __unserialize(array $serialized): void
|
||||
{
|
||||
$this->attributes = unserialize($serialized) ?: [];
|
||||
$this->attributes = $serialized ?: [];
|
||||
}
|
||||
|
||||
public function getProvider(): Contracts\ProviderInterface
|
||||
{
|
||||
return $this->provider ?? throw new Exceptions\Exception('The provider instance doesn\'t initialized correctly.');
|
||||
}
|
||||
|
||||
public function setProvider(Contracts\ProviderInterface $provider): self
|
||||
{
|
||||
$this->provider = $provider;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
53
vendor/overtrue/socialite/src/UserInterface.php
vendored
53
vendor/overtrue/socialite/src/UserInterface.php
vendored
@@ -1,53 +0,0 @@
|
||||
<?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();
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?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();
|
||||
}
|
||||
Reference in New Issue
Block a user