Files
wordpress-theme-aksrt/src/Auth/OAuthProviderBroker.php
T
kate522andClaude Opus 5 35bb96e82f refactor: rename the theme brand and every identifier from AKSRT to Jio
Full-project rename. `git grep -i aksrt` is now empty apart from the
DBMigrator 3.3.0 changelog note that documents the rename itself.

Code identifiers
- PHP namespace AKSRT\ -> Jio\ (composer PSR-4 + 378 declarations)
- global constants AKSRT_* -> JIO_* (VERSION/DIR/URI, PAY_TYPE_*, CAPTCHA_*)
- procedural functions, hooks, options, meta keys, table names,
  cookies, query vars, ajax actions and nonces: aksrt_ -> jio_
- text domain aksrt -> jio; Theme Name -> Jio
- JS globals: aksrtData/aksrtAdminData/... -> jioData/jioAdminData/...,
  window.AKSRTCaptcha & friends -> window.JioCaptcha, Aksrt* -> Jio*
- Vue components Aks*.vue -> Jio*.vue (15 files renamed + imports)
- CSS classes/data-attrs/custom properties: aksrt- -> jio-
- REST namespace aksrt/v1 -> jio/v1 (incl. payment gateway callbacks)

Storage layer
- DB tables {prefix}aksrt_* -> {prefix}jio_*; SCHEMA_VERSION 3.2.0 -> 3.3.0
  so dbDelta creates the new names on install
- widget id_base aksrt_widget_* -> jio_widget_*
- uninstall.php drop list rebuilt from the actual migrator tables
  (dropped 3 stale entries, added the 17 missing ones)

Removed
- hardcoded https://api.aksrt.com/version.json default update endpoint;
  get_endpoint() now reads the 「更新端点」 setting and do_check() no-ops
  when it is empty

Files renamed: inc/helpers/aksrt-*.php -> jio-*.php (54),
assets/admin/src/components/form/Aks*.vue -> Jio*.vue (15).
Build artifacts regenerated: assets/css/build, assets/js/runtime,
assets/admin/build.

Verified: audit-psr4-paths errors=0, audit-admin-contracts errors=0
(warnings=56, unchanged baseline), 813/813 widget-system tests,
44/44 phpunit, php -l clean across all PHP.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-01 20:05:04 +08:00

184 lines
6.9 KiB
PHP

<?php
/**
* @package Jio
*/
namespace Jio\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(__('未配置此第三方登录平台', 'jio'));
}
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(__('未配置此第三方登录平台', 'jio'));
}
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(__('不支持的第三方登录平台', 'jio'));
}
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 获取失败', 'jio'));
}
$token = json_decode((string) wp_remote_retrieve_body($response), true);
if (empty($token['access_token'])) {
throw new \RuntimeException(__('Google token 获取失败', 'jio'));
}
$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 用户信息获取失败', 'jio'));
}
$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(__('不支持的第三方登录平台', 'jio'));
}
}