refactor: flatten src/AKSRT → src (drop theme-identifier dir)

Move all domain folders from src/AKSRT/{Domain} to src/{Domain}; remap
Composer PSR-4 "AKSRT\\": "src/"; update audit script + README + ADR
paths; remove dead tools/build-psr4-map.php (scanned deleted inc/classes).
This commit is contained in:
2026-08-02 22:06:06 +08:00
parent 56f1a8175f
commit 8c5b1555c9
285 changed files with 26 additions and 3600 deletions
+306
View File
@@ -0,0 +1,306 @@
<?php
/**
* @package AKSRT
*/
namespace AKSRT\Auth;
defined('ABSPATH') || exit;
class OAuthProxyClient {
private static $instance = null;
public static function get_instance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {}
/**
* 初始化:注册回调路由
*/
public function init(): void {
add_action('template_redirect', [$this, 'handle_proxy_callback']);
add_action('init', [$this, 'add_rewrite_rules']);
}
/**
* 添加 URL 重写规则
*/
public function add_rewrite_rules(): void {
add_rewrite_rule(
'^oauth/proxy/callback/?$',
'index.php?aksrt_proxy_callback=1',
'top'
);
add_filter('query_vars', function ($vars) {
$vars[] = 'aksrt_proxy_callback';
return $vars;
});
}
/**
* 生成代理登录 URL
*
* @param string $provider 平台标识
* @param string $action 操作类型: 'login' | 'bind'
* @return string 代理登录 URL
*/
public function get_proxy_auth_url(string $provider, string $action = 'login'): string {
$server_url = \AKSRT\Settings\Settings::oauth_proxy_server_url();
$secret = \AKSRT\Settings\Settings::oauth_proxy_secret();
if (empty($server_url) || empty($secret)) {
return '';
}
$back_url = home_url('/oauth/proxy/callback');
$uid = get_current_user_id();
$nonce = wp_create_nonce('aksrt_proxy_' . $provider . '_' . $uid);
$params = [
'provider' => $provider,
'agent_back_url' => $back_url,
'action' => $action,
'nonce' => $nonce,
'uid' => $uid,
'ts' => time(),
];
$params['sign'] = $this->sign($params, $secret);
$server_url = rtrim($server_url, '/');
return $server_url . '/oauth/proxy/' . $provider . '?' . http_build_query($params);
}
/**
* 处理代理回调(从服务端重定向回来)
*/
public function handle_proxy_callback(): void {
if (!get_query_var('aksrt_proxy_callback')) {
return;
}
$secret = \AKSRT\Settings\Settings::oauth_proxy_secret();
if (empty($secret)) {
wp_die(__('代理登录配置错误', 'aksrt'));
}
$sign = sanitize_text_field($_GET['sign'] ?? '');
$provider = sanitize_key($_GET['provider'] ?? '');
$action = sanitize_key($_GET['action'] ?? 'login');
if (empty($sign) || empty($provider)) {
wp_die(__('代理回调参数无效', 'aksrt'));
}
// 验证签名
$verify_params = $_GET;
unset($verify_params['sign']);
if (!$this->verify_sign($verify_params, $secret, $sign)) {
wp_die(__('代理回调签名验证失败', 'aksrt'));
}
// 验证时间戳(5分钟内有效)
$ts = (int) ($_GET['ts'] ?? 0);
if (abs(time() - $ts) > 300) {
wp_die(__('代理回调已过期,请重新登录', 'aksrt'));
}
// 提取用户数据
$provider_id = sanitize_text_field($_GET['provider_id'] ?? '');
if (empty($provider_id)) {
wp_die(__('代理回调缺少用户标识', 'aksrt'));
}
$user_data = [
'provider' => $provider,
'provider_id' => $provider_id,
'username' => sanitize_user($_GET['username'] ?? '', true),
'name' => sanitize_text_field($_GET['name'] ?? ''),
'email' => sanitize_email($_GET['email'] ?? ''),
'email_verified' => !empty($_GET['email_verified']),
'avatar_url' => esc_url_raw($_GET['avatar_url'] ?? ''),
'bio' => sanitize_text_field($_GET['bio'] ?? ''),
];
if ($action === 'bind') {
$this->handle_proxy_bind($provider, $user_data);
return;
}
$this->handle_proxy_login($provider, $user_data);
}
/**
* 处理代理登录
*/
private function handle_proxy_login(string $provider, array $user_data): void {
$user = $this->find_or_create_user_from_proxy($provider, $user_data);
// 未匹配已有账号 → 跳转绑定页
if (is_wp_error($user) && $user->get_error_code() === 'oauth_no_match') {
$error_data = $user->get_error_data();
$obk = 'aksrt_ob_' . wp_generate_password(24, false);
set_transient($obk, [
'provider' => $error_data['provider'],
'provider_id' => $error_data['user_data']['provider_id'] ?? '',
'user_data' => $error_data['user_data'],
'token' => [],
], 15 * MINUTE_IN_SECONDS);
$bind_url = aksrt_get_bind_url();
wp_safe_redirect(add_query_arg('obk', $obk, $bind_url));
exit;
}
if (is_wp_error($user)) {
wp_die(__('登录失败:', 'aksrt') . esc_html($user->get_error_message()));
}
// 登录成功
wp_set_auth_cookie($user->ID, true);
$redirect_url = function_exists('aksrt_get_user_center_url') ? aksrt_get_user_center_url() : home_url('/');
wp_safe_redirect(add_query_arg(['oauth_action' => 'login', 'oauth_bound' => $provider], $redirect_url));
exit;
}
/**
* 处理代理绑定(已登录用户绑定第三方账号)
*/
private function handle_proxy_bind(string $provider, array $user_data): void {
$current_uid = get_current_user_id();
if (!$current_uid) {
wp_safe_redirect(aksrt_get_login_url());
exit;
}
// 检查是否已被其他用户占用
$existing = $this->find_user_by_provider_meta($provider, $user_data['provider_id']);
if ($existing && (int) $existing->ID !== $current_uid) {
wp_die(__('该第三方账号已被其他用户绑定', 'aksrt'));
}
$this->bind_provider_to_user($current_uid, $provider, $user_data);
$redirect_url = function_exists('aksrt_get_user_center_url')
? add_query_arg(['oauth_action' => 'bind', 'oauth_bound' => $provider], aksrt_get_user_center_url('settings'))
: home_url('/');
wp_safe_redirect($redirect_url);
exit;
}
/**
* 查找或创建用户(代理模式)
*
* @return \WP_User|\WP_Error
*/
private function find_or_create_user_from_proxy(string $provider, array $user_data) {
$email = $user_data['email'] ?? '';
// 1. 通过 provider_id 查找
if (!empty($user_data['provider_id'])) {
$existing = $this->find_user_by_provider_meta($provider, $user_data['provider_id']);
if ($existing instanceof \WP_User) {
$this->ensure_binding_meta($existing->ID, $provider, $user_data);
return $existing;
}
}
// 2. 通过邮箱查找
if (!empty($email) && is_email($email)) {
$existing = get_user_by('email', $email);
if ($existing && !$existing instanceof \WP_Error) {
$this->ensure_binding_meta($existing->ID, $provider, $user_data);
return $existing;
}
}
// 3. 未匹配
return new \WP_Error('oauth_no_match', __('需要绑定已有账号', 'aksrt'), [
'provider' => $provider,
'user_data' => $user_data,
]);
}
/**
* 确保绑定 meta 存在
*/
private function ensure_binding_meta(int $user_id, string $provider, array $user_data): void {
update_user_meta($user_id, "aksrt_{$provider}_id", $user_data['provider_id'] ?? '');
$bindings = get_user_meta($user_id, 'aksrt_oauth_bindings', true) ?: [];
if (!is_array($bindings)) {
$bindings = [];
}
if (!in_array($provider, $bindings, true)) {
$bindings[] = $provider;
update_user_meta($user_id, 'aksrt_oauth_bindings', $bindings);
}
if (!empty($user_data['avatar_url'])) {
update_user_meta($user_id, 'aksrt_oauth_avatar', esc_url_raw($user_data['avatar_url']));
}
}
/**
* 绑定第三方账号到用户
*/
private function bind_provider_to_user(int $user_id, string $provider, array $user_data): void {
if (!empty($user_data['provider_id'])) {
update_user_meta($user_id, "aksrt_{$provider}_id", $user_data['provider_id']);
}
$bindings = get_user_meta($user_id, 'aksrt_oauth_bindings', true) ?: [];
if (!is_array($bindings)) {
$bindings = [];
}
if (!in_array($provider, $bindings, true)) {
$bindings[] = $provider;
update_user_meta($user_id, 'aksrt_oauth_bindings', $bindings);
}
if (!empty($user_data['avatar_url'])) {
update_user_meta($user_id, 'aksrt_oauth_avatar', esc_url_raw($user_data['avatar_url']));
}
}
/**
* 通过 provider meta 查找用户
*/
private function find_user_by_provider_meta(string $provider, string $provider_id): ?\WP_User {
if (empty($provider_id)) {
return null;
}
$users = get_users([
'meta_key' => "aksrt_{$provider}_id",
'meta_value' => $provider_id,
'number' => 1,
]);
return !empty($users[0]) ? $users[0] : null;
}
/**
* 生成 HMAC-SHA256 签名
*/
private function sign(array $data, string $secret): string {
unset($data['sign']);
ksort($data);
$payload = http_build_query($data);
return hash_hmac('sha256', $payload, $secret);
}
/**
* 验证 HMAC-SHA256 签名
*/
private function verify_sign(array $data, string $secret, string $expected_sign): bool {
$computed = $this->sign($data, $secret);
return hash_equals($computed, $expected_sign);
}
}