https://a.storyblok.com/f/270183/105390/eca54dcd56/e_2fa-wordpress_1200x600.jpg

Nexmo Verify APIを使ってWordPressに2要素認証を追加する

最終更新日 May 13, 2021

所要時間:1 分

はじめに

セキュリティ侵害が増加する中、ウェブサイトとそのユーザーを保護することは、今日ほど切実な問題ではありません。このチュートリアルでは、Nexmo Verify APIを使ってWordPressに2FA(二要素認証)を設定します。この設定により、ユーザーがログインしようとすると、プロフィールに登録されている携帯電話番号にSMSか電話がかかってきて、固有のコードが表示され、有効なコードを入力するとログインできるようになります。

このチュートリアルの最後には、WordPressプラグイン構築の基本を学び、Nexmo PHPライブラリを使用してNexmo APIとWordPressを統合する方法を十分に理解していることでしょう。それでは始めましょう!

Nexmo Verify APIについて

Verify APIは、あらゆるシステム上で二要素認証を行うためのNexmoのプラグ・アンド・プレイ・ソリューションです。プロセスは簡単です。 検証送信エンドポイントを呼び出すと、NumbersmoはSMS/コールで携帯番号にユニークなコードを送り、リクエストIDを返します。ユーザーのコードで 確認エンドポイントを呼び出すと、Nexmoはコードが有効かどうかに応じてステータスを返します。簡単でしょう?

私がNexmo Verifyを特に気に入っているのは、ワークフローというものがあるからです。ワークフローを使えば、ユーザーがSMSで期限内にコードを受け取らなかった場合に備えて、複数のフォールバックオプションを設定することができます。ワークフローについてはこちらをご覧ください。 こちら.

始めるために必要なもの

WordPressプラグインの作成

WordPressのプラグインは、WordPressのpluginsフォルダに新しいフォルダを追加するだけで作成できますが、本当に効率的な方法は、軽量なボイラープレートを使用して開始することです。ボイラープレートは、すべてのファイルとクラスを標準的な方法でセットアップするのに役立ちます。このチュートリアルでは wppbボイラープレートを使用します。ウェブサイトに詳細を記入し、プラグインをビルドするボタンをクリックするだけでプラグインボイラープレートがダウンロードされます。

Wordpress Plugin Boilerplate GeneratorWordpress Plugin Boilerplate Generator

zipファイルを解凍し、WordPressのpluginsフォルダに入れます。次に、WordPressの管理画面に移動し、インストール済みのプラグインページに移動してプラグインを有効化します。

PluginsPlugins

ユーザーストーリー

WordPressで2FAを設定することを目標に、アイデアを実行可能なユーザーストーリー/ステップに分割し、上から下へ実装していきましょう:

  • WordPressのユーザー・プロフィール設定で、ユーザーの2FA携帯番号と2FAを有効にしているかどうかのカスタム・フィールドが必要です。

  • ログイン時にユーザーの携帯電話番号にコードを送信する。

  • ユーザーが受け取ったコードを入力し、コードをVerifyするためのフォームを用意します。

WordPressのアクションとフィルタを理解する

WordPressで行う編集のほとんどは、既存のWordPressのアクションやフィルターに関数をフックすることです; アクションは、WordPress で特定のイベントが発生したときに実行される関数です。アクションとは、WordPress内で特定のイベントが発生したときに実行される関数のことです。したがって、特定のイベントが発生したときに関数を実行させたい場合、例えばユーザーがログインしたときに実行させたい場合は、ログイン関連のアクションに関数をフックすることになります。もう一方は フィルター関数の結果を操作するためにフィルタを使うことができます。

このように既存のアクションに関数をフックする:

add_action( 'action_name', 'name_of_your_function' );

このように関数をフィルターにフックする:

add_filter( 'filter_name', 'name_of_your_function' );

ユーザー・カスタム・フィールド

この記事を簡潔にするため、以下はそのリンクである。 リンクをクリックして、WordPressのユーザー・プロフィール設定に携帯電話番号と2FA有効チェックボックス・フィールドを追加するコードをご覧ください。このセットアップで、ユーザー設定ページは次のようになります:

Nexmo 2FANexmo 2FA

Nexmo PHPライブラリの追加

Nexmoでは、以下のライブラリをインストールすることを推奨しています。 PHPライブラリComposerをサーバー/ローカルシステムにセットアップする必要があります。Composerをセットアップしていない場合は、Nexmoが推奨する2つのガイドを参照してください: GetComposer.orgまたは Scotch.io

Composerをインストールした状態でターミナルを開き、プラグインのルート・フォルダーに移動して実行する:

composer require nexmo/client

というフォルダが作成されます。 vendorという新しいフォルダが作成され、その中にNexmoのPHPライブラリが含まれます。このライブラリをプラグインに組み込むには、プラグインのルートのPHPファイルに次の行を追加するだけです。

require_once plugin_dir_path( __FILE__ ) . 'vendor/autoload.php';

Nexmoクラスの初期化

NexmoのPHPライブラリを使用して呼び出しを行う前に、Nexmoクラスを初期化し、その後のリクエストにクライアントオブジェクトを使用する必要があります。

$basic  = new \Nexmo\Client\Credentials\Basic(NEXMO_API_KEY, NEXMO_API_SECRET);
$client = new \Nexmo\Client(new \Nexmo\Client\Credentials\Container($basic));

ボイラープレートを使用している場合は、次のように編集します。 パブリッククラスファイルファイルを /publicフォルダにあるコンストラクトでNexmoライブラリを初期化し、クライアント・オブジェクトをprotected変数として設定します。

<?php
 
 
class Two_Factor_Auth_Nexmo_Public {
 
    protected $nexmo_client;
 
    public function __construct( $plugin_name, $version ) {
       $this->nexmo_client = new Nexmo\Client(new Nexmo\Client\Credentials\Basic(TWO_FACTOR_AUTH_NEXMO_KEY, TWO_FACTOR_AUTH_NEXMO_SECRET));
       
    }
}

検証リクエストの送信

ユーザストーリーに基づき、ユーザログインを傍受し、ユーザが2FAを有効にしているかチェックし、有効であれば 確認の送信リクエストを開始したい。これを実現するために authenticateWordPress アクションをフックすることになります。

<?php
 
class Two_Factor_Auth_Nexmo_Public {
 
    protected $nexmo_client;
 
    public function __construct( $plugin_name, $version ) {
        $this->nexmo_client = new Nexmo\Client(new Nexmo\Client\Credentials\Basic(TWO_FACTOR_AUTH_NEXMO_KEY, TWO_FACTOR_AUTH_NEXMO_SECRET));
        
 
        add_action( 'authenticate', array( $this, 'intercept_login_with_two_factor_auth' ), 10, 3 );
    }
 
    public function intercept_login_with_two_factor_auth( $user, $username, $password ) {
        $errors = array();
        $redirect_to = isset( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : admin_url();
        $remember_me = ( isset( $_POST['rememberme'] ) && $_POST['rememberme'] === 'forever' ) ? true : false;
        
        $_user = get_user_by( 'login', $username );
 
        if ( $_user ) {
            $this->verify_user( $_user, $redirect_to, $remember_me );
        }
 
        return $user;
    }

この関数を authenticateアクションにフックすることで、3つの変数を扱うことができる: $user, $usernameそして $passwordである。 $user変数は通常NULLだが、それでも構わない。必要なのは $usernameこれがあれば、WordPressの関数を呼び出してユーザーオブジェクトを取得することができます。ユーザーオブジェクトは、携帯電話番号や2FAを有効にしているかどうかなど、ユーザーの他のプロパティを取得するために必要です。

$_user = get_user_by( 'login', $username );// Function to get the user object

ユーザーのカスタムフィールドの値を取得するには、WordPressの関数 get_user_meta関数を使用します。ユーザープロファイル設定のコードで定義されているように、フィールド名は two_factor_auth_nexmo_enabledそして two_factor_auth_nexmo_mobile.

  private function verify_user( $user, $redirect_to, $remember_me, $errors = array() ) {
        
        $enabled_2fa = get_user_meta($user->ID, 'two_factor_auth_nexmo_enabled', true );
        $mobile = get_user_meta($user->ID, 'two_factor_auth_nexmo_mobile', true );
        
        if ( ! $mobile || ! $enabled_2fa) {
            return;
        }
 
        try {
            $verification = new \Nexmo\Verify\Verification($mobile, TWO_FACTOR_AUTH_NEXMO_SENDER_NAME);
            $this->nexmo_client->verify()->start($verification);
        }
        catch(Exception $e) {
            $errors = array( "Error sending verification request" );
        }
        
 
        $request_id = $verification->getRequestId();
        update_user_meta( $user->ID, 'two_factor_auth_nexmo_request_id', $request_id);
        
        wp_logout();
        
    }

必要な変数がすべて設定されている場合(携帯電話番号と2FAが有効になっているユーザー)、関数を呼び出して 認証送信リクエストを開始する関数を呼び出すと、Nexmoは一意のコードをユーザーに送信し、リクエストIDが返されます。次のステップでValidate code関数を呼び出すために使えるように、リクエストIDを保存しておくことが重要です。これを行う簡単な方法は、WordPress の update_user_meta関数に変数のキー識別子(ここでは two_factor_auth_nexmo_request_id) と変数 $request_id.

最後に logout関数を呼び出す。なぜそんなことをするのかと思うかもしれません。最初に述べたように、authenticateアクションはユーザーがログインに成功したときに起動されるからです。つまり、現実には、このコードはすべてユーザーがログインしたときに実行されるわけですが、少なくともまだそうしたいわけではありません。ユーザーをログインさせたいのは、コードを検証した後です。したがって、コードを送信した後にユーザーをログアウトさせ、最後のステップである、コードを検証してユーザーをログインさせます。

コードの検証

上記のセクションでユーザーにコードを送信しました。あとは、受け取ったコードを入力するフォームをユーザーに表示し、プロフィールに照らしてコードを検証してログインするだけです。

先ほど作成した verify_user関数をベースに、コード・バリデーション・フォームを追加します。

private function verify_user( $user, $redirect_to, $remember_me, $errors = array() ) {
        
        $enabled_2fa = get_user_meta($user->ID, 'two_factor_auth_nexmo_enabled', true );
        $mobile = get_user_meta($user->ID, 'two_factor_auth_nexmo_mobile', true );
        
        if ( ! $mobile || ! $enabled_2fa) {
            return;
        }
 
        try {
            $verification = new \Nexmo\Verify\Verification($mobile, TWO_FACTOR_AUTH_NEXMO_SENDER_NAME);
            $this->nexmo_client->verify()->start($verification);
        }
        catch(Exception $e) {
            $errors = array( "Error sending verification request" );
        }
        
 
        $request_id = $verification->getRequestId();
        update_user_meta( $user->ID, 'two_factor_auth_nexmo_request_id', $request_id);
        
        wp_logout();
        nocache_headers();
        header('Content-Type: ' . get_bloginfo( 'html_type' ) . '; charset=' . get_bloginfo( 'charset' ) );
        login_header('Nexmo Two-Factor Authentication', '<p class="message">' . sprintf( 'Enter the PIN code sent to your mobile number ending in <strong>%1$s</strong>' , substr($mobile, -5) ) . '</p>');
 
        if(!empty($errors)) { 
        
        ?>
            <div id="login_error"><?php echo implode( '<br />', $errors ) ?></div>
        <?php  } ?>
 
        <form name="loginform" id="loginform" action="<?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ) ?>" method="post" autocomplete="off">
            <p>
                <label for="two_factor_auth_nexmo_pin_code">Code
                    <br />
                    <input type="number" name="two_factor_auth_nexmo_pin_code" id="two_factor_auth_nexmo_pin_code" class="input" value="" size="6" />
                </label>
            </p>
            <p class="submit">
                <input type="submit" name="wp-submit" id="wp-submit" class="button button-primary button-large" value="Verify" />
                <input type="hidden" name="log" value="<?php echo esc_attr( $user->user_login ) ?>" />
                <input type="hidden" name="two_factor_auth_nexmo_request_id" value="<?php echo esc_attr( $request_id ) ?>" />
                <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ) ?>" />
 
                <?php if ( $remember_me ) : ?>
                    <input type="hidden" name="rememberme" value="forever" />
                <?php endif; ?>
            </p>
        </form>
 
        <?php 
        
        login_footer( 'two_factor_auth_nexmo_pin_code' );
 
        exit;
    }

NB:私は自分のHTMLをこのClassメソッドの中に入れていますが、あなたのHTMLを別のファイルに入れてインクルードすることもできます。

上記のコードで、2FAを有効にしたアカウントにログインしようとすると、次のようなページが表示されるはずです。

Wordpress PinWordpress Pin

この login_header関数は、ユーザーの携帯電話番号の下5桁を表示する小さなセクションをフォームの上に追加します。

このビューの <form>は WordPress のログインフォームの複製で、ほんの少し変更が加えられています。ブラウザでWordPressのログインフォームを見ると、ユーザー名の入力フィールドに"<strong>log</strong>"というname属性があることに気づくでしょう。これはWordPressがユーザー名を取得する方法なので、そのままにしておいてください。最初のログインセッションからのリダイレクトとremember me preferenceの経験を維持するために、これらの変数をそれぞれの入力フィールド名で保持しますが、今回は非表示にします。最後に、Send Verificationリクエストの呼び出しからのリクエストIDを、ユーザーが入力したコードの値と同様に隠し入力フィールドに渡します。

フォームのパラメータは以下の通り:

  • log:ユーザー名

  • two_factor_auth_nexmo_pin_code:ユーザーが入力するコード

  • two_factor_auth_nexmo_request_id:初回リクエスト時のリクエストID

  • rememberme:初回ログインからの Remember me ステータス

  • redirect_to:ユーザーがログインフォームの前に特定のページにアクセスしようとしていた場合、URLへリダイレクトする。

重要な注意フォームのアクションURLはWordPressのログインURLルートのままです。 <?php echo esc_url( site_url( 'wp-login.php', 'login_post' ) ) ?>興味深いのは、インターセプト関数がauthenticateアクションにフックされているので、verify codeフォームでverifyボタンをクリックしてもインターセプト関数が実行され、ユーザーが入力したコードを検証するコードスニペットが追加されることです。

public function intercept_login_with_two_factor_auth( $user, $username, $password ) {
        $errors = array();
        $redirect_to = isset( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : admin_url();
        $remember_me = ( isset( $_POST['rememberme'] ) && $_POST['rememberme'] === 'forever' ) ? true : false;
        
        $_user = get_user_by( 'login', $username );
// New addition
        $saved_request_id =  ($_user) ? get_user_meta($_user->ID, 'two_factor_auth_nexmo_request_id', true ) : null;
        $nexmo_pin_code = isset( $_POST['two_factor_auth_nexmo_pin_code'] ) ? $_POST['two_factor_auth_nexmo_pin_code'] : false;
        $nexmo_request_id = isset( $_POST['two_factor_auth_nexmo_request_id'] ) ? $_POST['two_factor_auth_nexmo_request_id'] : false;
        
        if ( $nexmo_request_id && $nexmo_pin_code && $saved_request_id == $nexmo_request_id ) {
            
            $verification = new \Nexmo\Verify\Verification($nexmo_request_id);
            try {
                $result = $this->nexmo_client->verify()->check($verification, $nexmo_pin_code);
                $response = $result->getResponseData();
                if ($response['status']  == "0") {
                    wp_set_auth_cookie( $_user->ID, $remember_me );
                    wp_safe_redirect( $redirect_to );
                    exit;
                }
            }
            catch(Exception $e) {
                // handle invalid  code
                if ($e->getCode() == 16){
                    $errors = array( "Invalid PIN code" );
                }
                $this->verify_user( $_user, $redirect_to, $remember_me,$errors );
            }
        }
// End of addition
        if ( $_user ) {
            $this->verify_user( $_user, $redirect_to, $remember_me );
        }
 
        return $user;
    }

上記の追加では、ログイン・リクエストのPOSTデータをチェックするために 'two_factor_auth_nexmo_pin_code''two_factor_auth_nexmo_request_id'キーが設定されているかどうかをチェックしています。もし設定されていれば、コードを検証するリクエストです。正しいユーザのコードを検証していることを確認するために、POST データのリクエスト ID とユーザのプロファイルに保存されているリクエスト ID を比較します。 チェック検証関数を呼び出し、入力されたコードが正しいことを確認します。もし正しければ、そのユーザーにWordPress認証クッキーを設定し、ダッシュボードにリダイレクトします。

wp_set_auth_cookie( $_user->ID, $remember_me );
wp_safe_redirect( $redirect_to );

そうでない場合は、単に verify_user関数を再度呼び出し、新しい検証コードを送信すればよい。

ここに リンクをクリックしてください。

結論

このチュートリアルでは、WordPressプラグインの構築、Nexmo PHPライブラリの統合、Nexmo Verify APIの使用についての基本を学びました。このチュートリアルがお役に立てたなら幸いです。 リンク. お読みいただきありがとうございました!

シェア:

https://a.storyblok.com/f/270183/384x384/6293d5e6de/douglaskendyson.png
Douglas Kendyson

Douglas is a full stack software engineer with a keen interest to marketing, customer growth and data analytics. When he’s not coding, he’s probably watching way too many TV shows.