Twilioブログ

TwilioとLaravelを使った二要素認証APIの作り方

こんにちは、katsu.tです。

企業のセキュリティ意識が高まっている昨今、顧客が安全にアカウントを利用できるように多くのサービスが二要素認証を取り入れています。

なかでもSMSや電話を使った音声での二要素認証機能は、簡単にアカウントが発行できるメールでの二要素認証よりも確実に本人認証できると注目されています。
そこで今回の記事では、電話番号を用いた「二要素認証API」を、TwilioとPHPのフレームワークであるLaravelを使って作成する方法をご紹介いたします。

※二段階認証と二要素認証の違いについては、こちらの記事をご覧ください。

事前準備

作るAPIの想定

TwilioとLaravelを用いて作るAPIには、「認証コードを送信するAPI」と「送信された認証コードを検証するAPI」の2種類があります。

認証コード送信API

SMSまたは電話を使って、対象の電話番号に認証コードを送信します。

エンドポイント
・api/verifications

パラメータ

パラメータ名 役割 設定値
to 認証コードを送信する電話番号 例:+8190xxxxxxxx
channel 送信するチャネル sms/voice
利用例
curl -X POST http://localhost:8000/api/verifications \
--data-urlencode 'to=+8190xxxxxxxx' \
--data-urlencode 'channel=sms'

認証コード検証API

送信された認証コードの検証に利用します。

エンドポイント
・api/validate

パラメータ

パラメータ名 役割 設定値
to 認証コードを送信した電話番号 例:+8190xxxxxxxx
code 検証する認証コード 例:123456
利用例
curl -X POST http://localhost:8000/api/validate \
--data-urlencode 'to=+8190xxxxxxxx' \
--data-urlencode 'code=123456'

APIの作り方

①新しいプロジェクトを作る

まずは新しいLaravelプロジェクトを作成し、作成したフォルダに移動します。

$ composer create-project laravel/laravel verify-system
$ cd verify-system

②.envファイルを修正する

次に、フォルダ内にある".envファイル"を修正していきます。
.envファイルの一番下にTwilioの情報を追記します。コメント部分は削除して追記してください。

TWILIO_SID=ACxxxxxxxxxxxxxxxx  // twilioコンソールから確認することができます。
TWILIO_TOKEN=xxxxxxxxxxxxxxxxxx  // twilioコンソールから確認することができます。
TWILIO_FROM=+14xxxxxxx  // twilioで購入したアメリカ番号を設定します。
TWILIO_FROM_VOICE=+8150xxxxxxx  // twilioで購入した日本番号を設定します。

③DBの設定を行う

続いてDBの設定を行いましょう。
本ブログでは、依存性の少ない軽量のRDB SQliteを利用します。


まず.envファイルのDBの項目を修正します。

修正前
DB_CONNECTION=mysql // 修正
DB_HOST=127.0.0.1 // 削除
DB_PORT=3306 // 削除
DB_DATABASE=laravel // 削除
DB_USERNAME=root // 削除
DB_PASSWORD= // 削除

↓

修正後
DB_CONNECTION=sqlite

sqlite用のDBファイルをdatabaseフォルダ内に作成します。

$ touch database/database.sqlite

DBの設定が完了したら、マイグレーションの作成を行います。

$ php artisan make:migration create_verifies_table

database/migrations/日付_create_verify_table.phppublic functions up()の中身を以下ソースコードで上書きします。

public function up()
    {
        Schema::create('verifies', function (Blueprint $table) {
            $table->id();
            $table->string('to'); // 送信先
            $table->string('code'); // 認証コード
            $table->string('status'); // 送信ステータス
            $table->timestamps();
        });
    }

DBのマイグレートを行います。

$ php artisan migrate

TwilioのSDKをインストールします。

$ composer require twilio/sdk

※次のようなエラーが表示されたら以下コマンドをお試しください。

Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 4096 bytes) in phar:///usr/local/Cellar/composer/1.8.3/bin/composer/src/Composer/DependencyResolver/RuleWatchGraph.php on line 52

Check https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors for more info on how to handle out of memory errors.
$ COMPOSER_MEMORY_LIMIT=-1 composer require twilio/sdk

④認証コード送信APIを作る

設定が完了したら、いよいよAPI作成のフェーズに入ります。

Programmable SMS と Programmable Voice を利用し、認証コードを送信する部分を作っていきましょう。

 

まず、Modelを作成します。

$ php artisan make:model Verify

続いて、Controllerを作成します。

$ php artisan make:controller VerificationsController

作成できたら、以下ソースコードで app/Http/Controller/VerificationsController.phpを上書きします。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Verify;
use Twilio\Rest\Client;

class VerificationsController extends Controller
{

    // 認証コードの送信
    public function verifications(Request $request)
    {

        $code = $this->generateCode(6);
        $verify = new Verify;
        $verify->to = $request->to;
        $verify->code = $code;

        $result = $this->sendCode($code,$request->channel,$request->to);
        
        if($result) {
            $verify->status = 'send';
            $verify->save();
            return response()->json([
                'message' => 'send success'
            ],200);
        } else {
            return response()->json([
                'message' => 'send failed'
            ],400);
        }
    }

    // 認証コード生成
    private function generateCode($length)
    {
        $max = pow(10, $length) - 1;
        $rand = random_int(0, $max);
        $code = sprintf('%0'. $length. 'd', $rand);

        return $code;
    }

    // 認証コード送信
    private function sendCode($code,$channel,$to) 
    {
        $client = new Client(env('TWILIO_SID'),env('TWILIO_TOKEN'));
        if($channel == 'sms') {
            $client->messages->create(
                $to,
                [
                    'from' => env( 'TWILIO_FROM' ),
                    'body' => 'あなたの認証コードは '.$code.' です。',
                ]);
            return true;
        } else if($channel == 'voice'){
            $client->calls->create(
                $to,
                env( 'TWILIO_FROM_VOICE' ), // from
                [
                    "twiml" => "<Response><Say language='ja-Jp'>あなたの認証コードは".join(',',str_split($code))."です。</Say></Response>"
                ]);
            return true;
        } else {
            return false;
        }
    }
}

続いて、routes/api.phpに認証コード送信APIを追加します。

use App\Http\Controllers\VerificationsController;

~~~ 中略 ~~~

Route::post('/verifications',[VerificationsController::class,'verifications']);

以上で認証コード送信APIの実装は完了です。

⑤認証コードの検証API

次に、送信した認証コードの検証APIを作っていきます。
以下ソースコードを app/Http/Controller/VerificationsController.php に追記します。

public function verificationCheck(Request $request)
    {
        // 送信先と認証コードを元に送信済みで未検証なレコードを取得
        $verifies = Verify::where('to',$request->to)->where('code',$request->code)->whereNotIn('status',['verified'])->get();
        // レコードがあれば認証成功
        if(count($verifies) == 1) {
            $verify = $verifies->first();
            $verify->status = 'verified';
            $verify->save();
            return response()->json([
                'message' => 'verification success'
            ],200);
        } else {
            // レコードがなければ認証失敗
            return response()->json([
                'message' => 'verification failuer'
            ],401);
        }
    }

続いて、routes/api.php に認証コード送信APIを追加します。

Route::post('/validate',[VerificationsController::class,'verificationCheck']);

以上で検証APIの作成は完了です。

APIのテスト

APIの作成が完了したら、作ったAPIが正しく機能しているかをテストしていきましょう。
まずは、作成したサーバーを起動します。

$ php artisan serve

起動後、APIを試します。

$ curl -X POST http://localhost:8000/api/verifications \
--data-urlencode 'to=+8190xxxxxxxx' \
--data-urlencode 'channel=sms'

toに設定した電話番号にSMSが届いていることを確認しましょう。
※SMSが受信できなかった場合は、こちらのFAQをご確認ください。

無事にSMSが届いたら、送信された認証コードをAPIで検証します。

$ curl -X POST http://localhost:8000/api/validate \
--data-urlencode 'to=+8190xxxxxxxx' \
--data-urlencode 'code=209336'

200が返却されたら、認証コードの検証成功です。

まとめ

今回の記事では、独自で「二要素認証API」を作成する方法をご紹介いたしました。
すでにメールでの二要素認証を導入していて、SMSや電話を使った音声での二要素認証についてはこれから導入を検討していく……といった方々の参考になれば幸いです。

またTwilioでは、今回ご紹介した内容に近い二要素認証が簡単に導入できるAPIを2つご用意しております。電話番号を用いた認証を低コストで導入できますので、二要素認証の導入自体がまだの方はぜひご検討ください。

Twilio Verifyを使った二要素認証、二段階認証の実装方法
・Twilio Authyを用いた二要素認証、二段階認証の実装方法

アプリケーションエンジニア 葛 智紀
アプリケーションエンジニア 葛 智紀

前職でiOS、Androidのネイティブアプリケーション開発、AngularやLaravelを用いたウェブアプリケーション開発に従事。KDDIウェブコミュニケーションズではTwilioの最新情報の発信やTwilioを用いた地域課題解決を担当。 個人では、Google Developer Group Tokyoのオーガナイザーを務める。

お問い合わせはこちら

Share!!

  • お役立ち情報
  • イベント情報
  • 相談会申込
  • 導入事例