/** * ========================================================================================= * Welcart 2段階認証機能(A〜E 最終解決版:同期・キャッシュ対策済み) * ========================================================================================= */ // A. セッション開始 add_action('init', function() { if (!session_id() && !is_admin()) { session_start(); } }, 1); // B. ログイン直後に認証コードを生成・送信 add_action('usces_action_after_login', 'send_2fa_code_final'); function send_2fa_code_final() { $user = wp_get_current_user(); // 管理者はスキップ if (in_array('administrator', (array)$user->roles)) return; // 認証コード生成 $code = (string)rand(100000, 999999); // データベースに確実に保存し、キャッシュをクリアする update_user_meta($user->ID, '_welcart_2fa_code', $code); update_user_meta($user->ID, '_welcart_2fa_pending', '1'); update_user_meta($user->ID, '_welcart_2fa_timestamp', time()); clean_user_cache($user->ID); // キャッシュを破棄して即時反映させる if (!session_id()) session_start(); $_SESSION['welcart_2fa_pending'] = true; // メール送信 $shop_name = get_option('blogname'); $to = usces_memberinfo('mailaddress1', 'return'); if (empty($to)) $to = $user->user_email; $subject = "【" . $shop_name . "】認証コードのご案内"; $message = "ログインを完了するには、以下のコードを入力してください。\n\n認証コード: " . $code . "\n\n※このコードは10分間有効です。"; wp_mail($to, $subject, $message); } // C. ガード処理:未認証なら強制的にマイページへリダイレクト add_action('template_redirect', function() { if (!is_user_logged_in()) return; $user_id = get_current_user_id(); if (current_user_can('administrator')) return; // 最新のメタデータを取得するためにキャッシュをクリア clean_user_cache($user_id); $is_pending = get_user_meta($user_id, '_welcart_2fa_pending', true); if ($is_pending === '1') { // タイムアウトチェック(10分) $timestamp = get_user_meta($user_id, '_welcart_2fa_timestamp', true); if ($timestamp && (time() - $timestamp) > 600) { delete_user_meta($user_id, '_welcart_2fa_pending'); delete_user_meta($user_id, '_welcart_2fa_code'); delete_user_meta($user_id, '_welcart_2fa_timestamp'); wp_logout(); wp_safe_redirect(add_query_arg('2fa_timeout', '1', home_url('/usces-member/'))); exit; } $current_url = $_SERVER['REQUEST_URI']; if (strpos($current_url, 'usces-member') === false && strpos($current_url, 'wp-login.php') === false && strpos($current_url, 'admin-post.php') === false) { wp_safe_redirect(home_url('/usces-member/')); exit; } } }, 1); // D. 認証照合処理 add_action('admin_post_verify_2fa_code', 'handle_2fa_verification_final'); add_action('admin_post_nopriv_verify_2fa_code', 'handle_2fa_verification_final'); function handle_2fa_verification_final() { if (!session_id()) session_start(); if (!isset($_POST['welcart_2fa_nonce']) || !wp_verify_nonce($_POST['welcart_2fa_nonce'], 'welcart_2fa_action')) { wp_die('セキュリティエラー:もう一度やり直してください。'); } $user_id = get_current_user_id(); clean_user_cache($user_id); $input_code = isset($_POST['auth_code']) ? trim(sanitize_text_field($_POST['auth_code'])) : ''; $saved_code = trim((string)get_user_meta($user_id, '_welcart_2fa_code', true)); if ($input_code !== '' && $input_code === $saved_code) { delete_user_meta($user_id, '_welcart_2fa_pending'); delete_user_meta($user_id, '_welcart_2fa_code'); delete_user_meta($user_id, '_welcart_2fa_timestamp'); unset($_SESSION['welcart_2fa_pending']); wp_safe_redirect(home_url('/usces-member/?2fa_success=1')); exit; } else { wp_safe_redirect(add_query_arg('2fa_error', '1', home_url('/usces-member/'))); exit; } } // E. ログアウト時のクリーンアップ add_action('wp_logout', function() { $user_id = get_current_user_id(); if ($user_id) { delete_user_meta($user_id, '_welcart_2fa_pending'); delete_user_meta($user_id, '_welcart_2fa_code'); delete_user_meta($user_id, '_welcart_2fa_timestamp'); } if (session_id()) { unset($_SESSION['welcart_2fa_pending']); } });