ID, $provider, $identity); return $user; } if ( OAuthProviderCatalog::bind_type() === 'auto' && !empty($identity['email_verified']) && is_email((string) ($identity['email'] ?? '')) ) { $user = get_user_by('email', sanitize_email((string) $identity['email'])); if ($user instanceof \WP_User) { $result = self::bind($user->ID, $provider, $identity); return is_wp_error($result) ? $result : $user; } } return new \WP_Error('oauth_no_match', __('需要绑定已有账号', 'aksrt'), [ 'provider' => $provider, 'user_data' => $identity, ]); } public static function find(string $provider, string $provider_id): ?\WP_User { $provider = sanitize_key($provider); if (!OAuthProviderCatalog::is_binding_provider($provider) || $provider_id === '') { return null; } $users = get_users([ 'meta_key' => 'aksrt_' . $provider . '_id', 'meta_value' => $provider_id, 'number' => 1, 'fields' => 'all', ]); return !empty($users[0]) && $users[0] instanceof \WP_User ? $users[0] : null; } public static function bind(int $user_id, string $provider, array $identity) { $provider = sanitize_key($provider); $provider_id = trim((string) ($identity['provider_id'] ?? '')); if ($user_id <= 0 || !OAuthProviderCatalog::is_binding_provider($provider) || $provider_id === '') { return new \WP_Error('oauth_binding_invalid', __('第三方账号信息无效', 'aksrt')); } $scope = 'identity:' . $provider . ':' . $provider_id; $lock = OAuthTransactionStore::acquire_lock($scope, 20); if ($lock === false) { return new \WP_Error('oauth_binding_busy', __('该第三方账号正在绑定,请稍后重试', 'aksrt')); } try { $existing = self::find($provider, $provider_id); if ($existing && (int) $existing->ID !== $user_id) { return new \WP_Error('oauth_binding_conflict', __('该第三方账号已被其他用户绑定', 'aksrt')); } update_user_meta($user_id, 'aksrt_' . $provider . '_id', $provider_id); $bindings = get_user_meta($user_id, 'aksrt_oauth_bindings', true); $bindings = is_array($bindings) ? array_values(array_intersect($bindings, OAuthProviderCatalog::all_binding_keys())) : []; if (!in_array($provider, $bindings, true)) { $bindings[] = $provider; } update_user_meta($user_id, 'aksrt_oauth_bindings', array_values(array_unique($bindings))); if (!empty($identity['avatar_url'])) { update_user_meta($user_id, 'aksrt_oauth_avatar', esc_url_raw((string) $identity['avatar_url'])); } return true; } finally { OAuthTransactionStore::release_lock($scope, (string) $lock); } } public static function unbind(int $user_id, string $provider) { $provider = sanitize_key($provider); if ($user_id <= 0 || !OAuthProviderCatalog::is_binding_provider($provider)) { return new \WP_Error('oauth_unbind_invalid', __('第三方账号类型无效', 'aksrt')); } if (!self::has_recovery_after_unbind($user_id, $provider)) { return new \WP_Error('oauth_last_login_method', __('请先设置其他登录或找回方式,再解除当前绑定', 'aksrt')); } $bindings = get_user_meta($user_id, 'aksrt_oauth_bindings', true); $bindings = is_array($bindings) ? $bindings : []; $bindings = array_values(array_diff($bindings, [$provider])); update_user_meta($user_id, 'aksrt_oauth_bindings', $bindings); delete_user_meta($user_id, 'aksrt_' . $provider . '_id'); delete_user_meta($user_id, 'aksrt_' . $provider . '_token'); return true; } public static function complete_login(\WP_User $user, bool $remember = true): void { wp_set_current_user($user->ID); wp_set_auth_cookie($user->ID, $remember); do_action('wp_login', $user->user_login, $user); } public static function bindings(int $user_id): array { $bindings = get_user_meta($user_id, 'aksrt_oauth_bindings', true); return is_array($bindings) ? array_values(array_intersect($bindings, OAuthProviderCatalog::all_binding_keys())) : []; } private static function refresh(int $user_id, string $provider, array $identity): void { $bindings = self::bindings($user_id); if (!in_array($provider, $bindings, true)) { $bindings[] = $provider; update_user_meta($user_id, 'aksrt_oauth_bindings', array_values(array_unique($bindings))); } if (!empty($identity['avatar_url'])) { update_user_meta($user_id, 'aksrt_oauth_avatar', esc_url_raw((string) $identity['avatar_url'])); } } private static function has_recovery_after_unbind(int $user_id, string $provider): bool { $remaining = array_values(array_diff(self::bindings($user_id), [$provider])); if ($remaining !== []) { return true; } if (get_user_meta($user_id, 'aksrt_phone_verified', true) === '1') { return true; } $user = get_user_by('id', $user_id); return $user instanceof \WP_User && is_email($user->user_email); } }