184 lines
7.0 KiB
PHP
184 lines
7.0 KiB
PHP
<?php
|
|
/**
|
|
* @package AKSRT
|
|
*/
|
|
|
|
namespace AKSRT\Auth;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
final class OAuthProviderBroker {
|
|
|
|
public function auth_url(string $provider, string $redirect_uri, string $state): string {
|
|
$config = OAuthProviderCatalog::provider_config($provider);
|
|
if (!$config || !$config['configured']) {
|
|
throw new \RuntimeException(__('未配置此第三方登录平台', 'aksrt'));
|
|
}
|
|
if ($provider === 'google') {
|
|
return 'https://accounts.google.com/o/oauth2/v2/auth?' . http_build_query([
|
|
'client_id' => $config['client_id'],
|
|
'redirect_uri' => $redirect_uri,
|
|
'response_type' => 'code',
|
|
'scope' => 'openid email profile',
|
|
'state' => $state,
|
|
]);
|
|
}
|
|
$oauth = $this->client($provider, $config, $redirect_uri);
|
|
$scope = $provider === 'github' ? 'read:user user:email' : null;
|
|
return (string) $oauth->getAuthUrl($redirect_uri, $state, $scope);
|
|
}
|
|
|
|
public function identity(string $provider, string $code, string $redirect_uri, string $state): array {
|
|
$config = OAuthProviderCatalog::provider_config($provider);
|
|
if (!$config || !$config['configured']) {
|
|
throw new \RuntimeException(__('未配置此第三方登录平台', 'aksrt'));
|
|
}
|
|
if ($provider === 'google') {
|
|
return $this->google_identity($config, $code, $redirect_uri);
|
|
}
|
|
$oauth = $this->client($provider, $config, $redirect_uri);
|
|
$oauth->getAccessToken($state, $code, $state);
|
|
if ($provider === 'qq') {
|
|
$openid = (string) $oauth->getOpenID();
|
|
$info = (array) $oauth->getUserInfo();
|
|
return $this->normalize($provider, $openid, $info);
|
|
}
|
|
$info = (array) $oauth->getUserInfo();
|
|
if ($provider === 'github') {
|
|
return $this->github_identity($oauth, $info);
|
|
}
|
|
return $this->normalize($provider, '', $info);
|
|
}
|
|
|
|
private function client(string $provider, array $config, string $redirect_uri) {
|
|
switch ($provider) {
|
|
case 'github':
|
|
return new \Yurun\OAuthLogin\Github\OAuth2($config['client_id'], $config['client_secret'], $redirect_uri);
|
|
case 'gitee':
|
|
return new \Yurun\OAuthLogin\Gitee\OAuth2($config['client_id'], $config['client_secret'], $redirect_uri);
|
|
case 'qq':
|
|
return new \Yurun\OAuthLogin\QQ\OAuth2($config['client_id'], $config['client_secret'], $redirect_uri);
|
|
case 'weibo':
|
|
return new \Yurun\OAuthLogin\Weibo\OAuth2($config['client_id'], $config['client_secret'], $redirect_uri);
|
|
case 'weixin':
|
|
return new \Yurun\OAuthLogin\Weixin\OAuth2($config['client_id'], $config['client_secret'], $redirect_uri);
|
|
}
|
|
throw new \RuntimeException(__('不支持的第三方登录平台', 'aksrt'));
|
|
}
|
|
|
|
private function github_identity($oauth, array $info): array {
|
|
$email = '';
|
|
$email_verified = false;
|
|
$response = $oauth->http->header('Authorization', ' token ' . $oauth->accessToken)
|
|
->get('https://api.github.com/user/emails')
|
|
->body();
|
|
$emails = json_decode((string) $response, true);
|
|
foreach (is_array($emails) ? $emails : [] as $candidate) {
|
|
if (!empty($candidate['primary']) && !empty($candidate['verified']) && is_email((string) ($candidate['email'] ?? ''))) {
|
|
$email = sanitize_email((string) $candidate['email']);
|
|
$email_verified = true;
|
|
break;
|
|
}
|
|
}
|
|
return [
|
|
'provider' => 'github',
|
|
'provider_id' => (string) ($info['id'] ?? ''),
|
|
'username' => (string) ($info['login'] ?? ''),
|
|
'name' => (string) ($info['name'] ?? ''),
|
|
'email' => $email,
|
|
'email_verified' => $email_verified,
|
|
'avatar_url' => (string) ($info['avatar_url'] ?? ''),
|
|
'url' => (string) ($info['html_url'] ?? ''),
|
|
'bio' => (string) ($info['bio'] ?? ''),
|
|
];
|
|
}
|
|
|
|
private function google_identity(array $config, string $code, string $redirect_uri): array {
|
|
$response = wp_remote_post('https://oauth2.googleapis.com/token', [
|
|
'timeout' => 15,
|
|
'redirects' => 2,
|
|
'body' => [
|
|
'code' => $code,
|
|
'client_id' => $config['client_id'],
|
|
'client_secret' => $config['client_secret'],
|
|
'redirect_uri' => $redirect_uri,
|
|
'grant_type' => 'authorization_code',
|
|
],
|
|
]);
|
|
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
|
|
throw new \RuntimeException(is_wp_error($response) ? $response->get_error_message() : __('Google token 获取失败', 'aksrt'));
|
|
}
|
|
$token = json_decode((string) wp_remote_retrieve_body($response), true);
|
|
if (empty($token['access_token'])) {
|
|
throw new \RuntimeException(__('Google token 获取失败', 'aksrt'));
|
|
}
|
|
$profile_response = wp_remote_get('https://openidconnect.googleapis.com/v1/userinfo', [
|
|
'timeout' => 15,
|
|
'redirects' => 2,
|
|
'headers' => ['Authorization' => 'Bearer ' . $token['access_token']],
|
|
]);
|
|
if (is_wp_error($profile_response) || wp_remote_retrieve_response_code($profile_response) !== 200) {
|
|
throw new \RuntimeException(is_wp_error($profile_response) ? $profile_response->get_error_message() : __('Google 用户信息获取失败', 'aksrt'));
|
|
}
|
|
$info = json_decode((string) wp_remote_retrieve_body($profile_response), true);
|
|
return [
|
|
'provider' => 'google',
|
|
'provider_id' => (string) ($info['sub'] ?? ''),
|
|
'username' => (string) ($info['email'] ?? ''),
|
|
'name' => (string) ($info['name'] ?? ''),
|
|
'email' => sanitize_email((string) ($info['email'] ?? '')),
|
|
'email_verified' => !empty($info['email_verified']),
|
|
'avatar_url' => (string) ($info['picture'] ?? ''),
|
|
'locale' => (string) ($info['locale'] ?? ''),
|
|
];
|
|
}
|
|
|
|
private function normalize(string $provider, string $provider_id, array $info): array {
|
|
switch ($provider) {
|
|
case 'gitee':
|
|
return [
|
|
'provider' => $provider,
|
|
'provider_id' => (string) ($info['id'] ?? ''),
|
|
'username' => (string) ($info['login'] ?? ''),
|
|
'name' => (string) ($info['name'] ?? ''),
|
|
'email' => sanitize_email((string) ($info['email'] ?? '')),
|
|
'email_verified' => false,
|
|
'avatar_url' => (string) ($info['avatar_url'] ?? ''),
|
|
'url' => (string) ($info['html_url'] ?? ''),
|
|
'bio' => (string) ($info['bio'] ?? ''),
|
|
];
|
|
case 'qq':
|
|
return [
|
|
'provider' => $provider,
|
|
'provider_id' => $provider_id,
|
|
'username' => (string) ($info['nickname'] ?? ''),
|
|
'name' => (string) ($info['nickname'] ?? ''),
|
|
'email' => '',
|
|
'email_verified' => false,
|
|
'avatar_url' => (string) ($info['figureurl_qq_2'] ?? $info['figureurl_2'] ?? $info['figureurl'] ?? ''),
|
|
];
|
|
case 'weibo':
|
|
return [
|
|
'provider' => $provider,
|
|
'provider_id' => (string) ($info['id'] ?? ''),
|
|
'username' => (string) ($info['screen_name'] ?? ''),
|
|
'name' => (string) ($info['name'] ?? ''),
|
|
'email' => '',
|
|
'email_verified' => false,
|
|
'avatar_url' => (string) ($info['avatar_large'] ?? $info['profile_image_url'] ?? ''),
|
|
];
|
|
case 'weixin':
|
|
return [
|
|
'provider' => $provider,
|
|
'provider_id' => (string) ($info['openid'] ?? ''),
|
|
'username' => (string) ($info['nickname'] ?? ''),
|
|
'name' => (string) ($info['nickname'] ?? ''),
|
|
'email' => '',
|
|
'email_verified' => false,
|
|
'avatar_url' => (string) ($info['headimgurl'] ?? ''),
|
|
];
|
|
}
|
|
throw new \RuntimeException(__('不支持的第三方登录平台', 'aksrt'));
|
|
}
|
|
}
|