Files
wordpress-theme-aksrt/src/Auth/OAuthProviderBroker.php
T
2026-08-29 22:03:48 +08:00

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'));
}
}