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>
184 lines
6.9 KiB
PHP
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'));
|
|
}
|
|
}
|