Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: paypal providers #274

Merged
merged 3 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 37 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ $socialite = new SocialiteManager($config);

$url = $socialite->create('github')->redirect();

return redirect($url);
return redirect($url);
```

`callback.php`:
Expand Down Expand Up @@ -122,15 +122,15 @@ $config = [
'client_secret' => 'your-app-secret',
'redirect' => 'http://localhost/socialite/callback.php',
],

// 另外一个名字叫做 bar 的 github 应用
'bar' => [
'provider' => 'github', // <-- provider name
'client_id' => 'your-app-id',
'client_secret' => 'your-app-secret',
'redirect' => 'http://localhost/socialite/callback.php',
],

//...
];

Expand Down Expand Up @@ -159,7 +159,7 @@ $config = [
];

$socialite = new SocialiteManager($config);

$socialite->extend('myprovider', function(array $config) {
return new MyCustomProvider($config);
});
Expand All @@ -172,7 +172,7 @@ $app = $socialite->create('foo');
>👋🏻 你的自定义服务提供类必须实现`Overtrue\Socialite\Contracts\ProviderInterface` 接口

```php
class MyCustomProvider implements \Overtrue\Socialite\Contracts\ProviderInterface
class MyCustomProvider implements \Overtrue\Socialite\Contracts\ProviderInterface
{
//...
}
Expand Down Expand Up @@ -208,8 +208,8 @@ $app = $socialite->create('foo');
$config = [
'alipay' => [
// 这个键名还能像官方文档那样叫做 'app_id'
'client_id' => 'your-app-id',
'client_id' => 'your-app-id',

// 请根据官方文档,在官方管理后台配置 RSA2
// 注意: 这是你自己的私钥
// 注意: 不允许私钥内容有其他字符
Expand All @@ -219,7 +219,7 @@ $config = [
// 确保这里的值与你在服务后台绑定的地址值一致
// 这个键名还能像官方文档那样叫做 'redirect_url'
'redirect' => 'http://localhost/socialite/callback.php',

// 沙箱模式接入地址见 https://opendocs.alipay.com/open/220/105337#%E5%85%B3%E4%BA%8E%E6%B2%99%E7%AE%B1
'sandbox' => false,
]
Expand Down Expand Up @@ -252,7 +252,7 @@ $config = [
// or 'app_id'
'client_id' => 'your app id',

// or 'app_secret'
// or 'app_secret'
'client_secret' => 'your app secret',

// or 'redirect_url'
Expand Down Expand Up @@ -361,7 +361,7 @@ $config = [
// or 'app_id'
'client_id' => 'your app id',

// or 'app_secret'
// or 'app_secret'
'client_secret' => 'your app secret',

// or 'redirect_url'
Expand Down Expand Up @@ -391,7 +391,7 @@ $config = [
// or 'app_id'
'client_id' => 'your app id',

// or 'app_secret'
// or 'app_secret'
'client_secret' => 'your app secret',

// or 'redirect_url'
Expand All @@ -413,7 +413,7 @@ $larkDriver->withDefaultMode()->withAppTicket('app_ticket')->userFromCode('here

### [淘宝](https://open.taobao.com/doc.htm?docId=102635&docType=1&source=search)

其他配置与其他平台的一样,你能选择你想要展示的重定向页面类型通过使用 `withView()`
其他配置与其他平台的一样,你能选择你想要展示的重定向页面类型通过使用 `withView()`

```php
$authUrl = $socialite->create('taobao')->withView('wap')->redirect();
Expand Down Expand Up @@ -456,14 +456,32 @@ $authUrl = $socialite->create('taobao')->withView('wap')->redirect();
```php
$config = [
'coding' => [
'team_url' => 'https://{your-team}.coding.net',
'team_url' => 'https://{your-team}.coding.net',
'client_id' => 'your app id',
'client_secret' => 'your app secret',
'redirect' => 'redirect URL',
]
];
```

### [PayPal](https://developer.paypal.com/docs/log-in-with-paypal/)

您可能需要设置responseType,可以使用`withResponseType`函数进行设置,默认是`code` 还可以设置为`id_token` 或`code` & `id_token`

> https://developer.paypal.com/docs/log-in-with-paypal/integrate/generate-button/


```php
$config = [
'paypal' => [
'client_id' => 'AT******************',
'client_secret' => 'EK**************',
'sandbox' => false,
'redirect_url'=>"nativexo://paypalpay",
],
];
```

## 其他一些技巧

### Scopes
Expand Down Expand Up @@ -498,7 +516,7 @@ $socialite->withRedirectUrl($url)->redirect();
```php
<?php
session_start();

$config = [
//...
];
Expand All @@ -510,7 +528,7 @@ $socialite = new SocialiteManager($config);

$url = $socialite->create('github')->withState($state)->redirect();

return redirect($url);
return redirect($url);
```

### 检验回调的 `state`
Expand All @@ -520,10 +538,10 @@ return redirect($url);
```php
<?php
session_start();

$state = request()->query('state');
$code = request()->query('code');

// Check the state received with current session id
if ($state != hash('sha256', session_id())) {
exit('State does not match!');
Expand Down Expand Up @@ -596,7 +614,7 @@ mixed $user->getId();
?string $user->getEmail();
?string $user->getAvatar();
?string $user->getRaw();
?string $user->getAccessToken();
?string $user->getAccessToken();
?string $user->getRefreshToken();
?int $user->getExpiresIn();
?array $user->getTokenResponse();
Expand Down Expand Up @@ -648,6 +666,7 @@ $user = $socialite->userFromToken($accessToken);
- [Tapd - 用户授权说明](https://www.tapd.cn/help/show#1120003271001000093)
- [Line - OAuth 2.0](https://developers.line.biz/en/docs/line-login/integrate-line-login/)
- [Gitee - OAuth文档](https://gitee.com/api/v5/oauth_doc#/)
- [PayPal - OAuth文档](https://developer.paypal.com/docs/log-in-with-paypal/)



Expand Down
21 changes: 21 additions & 0 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,26 @@ $config = [
];
```

### [PayPal](https://developer.paypal.com/docs/log-in-with-paypal/)

You may need to set the responseType, which can be set using the `withResponseType` function. The default is `code` and can also be set to `id_token` or `code` & `id_token`

> https://developer.paypal.com/docs/log-in-with-paypal/integrate/generate-button/


```php
$config = [
'paypal' => [
'client_id' => 'AT******************',
'client_secret' => 'EK**************',
'sandbox' => false,
'redirect_url'=>"nativexo://paypalpay",
],
];
```



## Some Skill

### Scopes
Expand Down Expand Up @@ -627,6 +647,7 @@ $user = $socialite->userFromToken($accessToken);
- [Tapd - 用户授权说明](https://www.tapd.cn/help/show#1120003271001000093)
- [Line - OAuth 2.0](https://developers.line.biz/en/docs/line-login/integrate-line-login/)
- [Gitee - OAuth文档](https://gitee.com/api/v5/oauth_doc#/)
- [PayPal - OAuth文档](https://developer.paypal.com/docs/log-in-with-paypal/)

[![Sponsor me](https://github.com/overtrue/overtrue/blob/master/sponsor-me.svg?raw=true)](https://github.com/sponsors/overtrue)

Expand Down
169 changes: 169 additions & 0 deletions src/Providers/PayPal.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
<?php

namespace Overtrue\Socialite\Providers;

use JetBrains\PhpStorm\Pure;
use Overtrue\Socialite\Contracts;
use Overtrue\Socialite\User;

/**
* Class PayPal
* @author zhiqiang
* @package Overtrue\Socialite\Providers
* @see https://developer.paypal.com/docs/log-in-with-paypal/
*/
class PayPal extends Base
{
public const NAME = 'paypal';

protected string $scopeSeparator = ' ';
/**
* @var string|null
* code or id_token
*/
protected ?string $responseType = Contracts\RFC6749_ABNF_CODE;
protected string $flowEntry = 'static';

protected string $authUrl = 'https://www.paypal.com/signin/authorize';
protected string $tokenURL = "https://api.sandbox.paypal.com/v1/oauth2/token";
protected string $userinfoURL = "https://api.paypal.com/v1/identity/openidconnect/userinfo";

protected array $scopes = [
'openid', 'profile', 'email', 'address'
];

protected bool $sandbox = true;

public function __construct(array $config)
{
parent::__construct($config);
$this->sandbox = (bool)$this->config->get('sandbox', false);
if ($this->sandbox) {
$this->authUrl = 'https://www.sandbox.paypal.com/signin/authorize';
$this->tokenURL = 'https://api-m.sandbox.paypal.com/v1/oauth2/token';
$this->userinfoURL = 'https://api-m.sandbox.paypal.com/v1/identity/openidconnect/userinfo';
}
}

/**
* @param string|null $responseType
* @return $this
* @see https://developer.paypal.com/docs/log-in-with-paypal/integrate/generate-button/
*/
public function withResponseType(?string $responseType)
{
$this->responseType = $responseType;
return $this;
}

protected function getAuthUrl(): string
{
return $this->buildAuthUrlFromBase($this->authUrl);
}

protected function getCodeFields(): array
{
$fields = \array_merge(
[
'flowEntry' => $this->flowEntry,
Contracts\RFC6749_ABNF_CLIENT_ID => $this->getClientId(),
Contracts\RFC6749_ABNF_RESPONSE_TYPE => $this->responseType,
Contracts\RFC6749_ABNF_SCOPE => $this->formatScopes($this->scopes, $this->scopeSeparator),
Contracts\RFC6749_ABNF_REDIRECT_URI => $this->redirectUrl,
],
$this->parameters
);

if ($this->state) {
$fields[Contracts\RFC6749_ABNF_STATE] = $this->state;
}
return $fields;
}


protected function getTokenUrl(): string
{
return $this->tokenURL;
}

/**
* @param string $code
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Overtrue\Socialite\Exceptions\AuthorizeFailedException
* @see https://developer.paypal.com/docs/log-in-with-paypal/integrate/#link-getaccesstoken
*/
public function tokenFromCode(string $code): array
{
$response = $this->getHttpClient()->post(
$this->getTokenUrl(),
[
'form_params' => [
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_AUTHORATION_CODE,
Contracts\RFC6749_ABNF_CODE => $code,
],
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Basic ' . \base64_encode(\sprintf('%s:%s', $this->getClientId(), $this->getClientSecret())),
],
]
);
return $this->normalizeAccessTokenResponse((string)$response->getBody());
}

/**
* @param string $refreshToken
* @return mixed
* @throws \GuzzleHttp\Exception\GuzzleException
* @throws \Overtrue\Socialite\Exceptions\AuthorizeFailedException
* @see https://developer.paypal.com/docs/log-in-with-paypal/integrate/#link-exchangerefreshtokenforaccesstoken
*/
public function refreshToken(string $refreshToken): mixed
{
$response = $this->getHttpClient()->post(
$this->getTokenUrl(),
[
'form_params' => [
Contracts\RFC6749_ABNF_GRANT_TYPE => Contracts\RFC6749_ABNF_REFRESH_TOKEN,
Contracts\RFC6749_ABNF_REFRESH_TOKEN => $refreshToken,
],
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Basic ' . \base64_encode(\sprintf('%s:%s', $this->getClientId(), $this->getClientSecret())),
],
]
);
return $this->normalizeAccessTokenResponse((string)$response->getBody());
}

/**
* @param string $token
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
* @see https://developer.paypal.com/docs/api/identity/v1/#userinfo_get
*/
protected function getUserByToken(string $token): array
{
$response = $this->getHttpClient()->get(
$this->userinfoURL,
[
'headers' => [
'Content-Type' => 'application/x-www-form-urlencoded',
'Authorization' => 'Bearer ' . $token,
],
]
);
return $this->fromJsonBody($response);
}

#[Pure]
protected function mapUserToObject(array $user): Contracts\UserInterface
{
$user[Contracts\ABNF_ID] = $user['user_id'] ?? null;
$user[Contracts\ABNF_NICKNAME] = $user['given_name'] ?? $user['family_name'] ?? $user['middle_name'] ?? null;
$user[Contracts\ABNF_NAME] = $user['name'] ?? '';
$user[Contracts\ABNF_EMAIL] = $user[Contracts\ABNF_EMAIL] ?? null;
$user[Contracts\ABNF_AVATAR] = $user['picture'] ?? null;
return new User($user);
}
}
1 change: 1 addition & 0 deletions src/SocialiteManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class SocialiteManager implements Contracts\FactoryInterface
Providers\WeWork::NAME => Providers\WeWork::class,
Providers\Weibo::NAME => Providers\Weibo::class,
Providers\XiGua::NAME => Providers\XiGua::class,
Providers\PayPal::NAME => Providers\PayPal::class,
];

#[Pure]
Expand Down
Loading