LoginSignup
4
4

Google Authenticatorでの2段階認証実装

Posted at

はじめに

昨今、様々なログイン時に使用されている2段階認証の実装備忘録です。

PHPでの実装にあたり、PHPGangsta/GoogleAuthenticatorを使用している方を見つけたので、参考に組んでみました。

認証の流れ

フロントでAPIを呼び出し、
返却されたQRコードを画面に表示する手法で実装しました。

大まかな流れは以下になります。

  1. ユーザー登録
    同時に秘密鍵をDBに登録
  2. ログイン後、認証ページに移動
  3. QRコードを表示
  4. Google Authenticatorで読み取る
  5. 表示された6桁のコードを入力して認証

実装の手順

➀Composerインストール

composer show --available phpgangsta/googleauthenticator
composer require --prefer-dist phpgangsta/googleauthenticator:dev-master

➁秘密鍵のDB登録

まずは秘密鍵を生成してDBに登録します。
今回はユーザーの登録時に秘密鍵を生成します。

RecipientController.php
$GangstaModel = new GoogleAuthenticatorFileTransferModel();
$secret = $GangstaModel->createSecret();

// フロントで入力されたユーザー情報と作成した秘密鍵をDBへ保存
$RecipientModel->createRecipient(
    $id
    , $name
    , $tel
    , $secret
);

➂QRコード生成

登録済ユーザーがログインを行った際に、
②で保存した秘密鍵を使用してQRコードを生成します。
QRコードを生成できたらフロントにURLを返却します。

RecipientController.php
$GangstaModel = new GoogleAuthenticatorFileTransferModel();

// 秘密鍵取得
$secret = $RecipientModel->getSecret($id);
// QRコード生成
$qrCode = $GangstaModel->createQrCode($secret);

return response()->json(['qrCode' => $qrCode]);

➃QRコード表示

バックエンドからQRコードのURLを取得できたら、
<img>srcにセットします。

ShowQrCode.vue
<template>
.
.

    <img :src="qrCode">
.
.

</template>
<script>
.
.
.
const qrCode = ref(); //QRコードのURL

const showQrCode = async() => {
    const url = 'api/showQrCode';
    const req = {
        token: token.value //ユーザー毎に一意の値
    };

    const response = await axios.post(url, req);

    if(response) {
        qrCode.value = response.data.qrCode;
    }
}

return {
    qrCode
}
.
.
.
</script>

処理が完了するとQRコードが画面に表示されるので、
Google Authenticatorで読み取ってコードを表示してください。

⑤認証処理

ログイン後、認証コード入力画面が表示されます。
Google Authenticatorに表示された6桁のコードを入力し、Laravelに送信します。

Authenticate.vue
const authenticate = async() => {
    const url = "api/authenticate";
    const req = {
        userId = userId.value,
        code = inputCode.value // 認証コード
    }

    const result = await axios.get(url, {params: req});

    if(result) {
        //2段階認証成功の場合、成功画面に遷移
        router.push('/success');
    }
}
RecipientController.php
public function checkOnetimeCode(Request $req) {
    $GangstaModel = new GoogleAuthenticatorFileTransferModel();
    $RecipientModel = new RecipientModel();

    $userId = $req->get('userId');
    $code = $req->get('code');
    // ユーザー作成時DBに保存した秘密鍵を取得
    $userSecret = RecipientModel->getSecret($userId);

    // 認証コードと秘密鍵を用いて整合性をチェック
    $result = $GangstaModel->checkOnetimeCode($code, $secret);

    // チェックが成功の場合、trueを返却
    if($result) {
        return true;
    }
}

おわりに

難しそうな印象を持っていましたが、実装は思っていたよりも単純でした。

今回はサンプルなのでエラー処理等を記述していません。
実際に導入する際は、きちんとハンドリングを実装する必要がありますね。

それでは。

参考サイト

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4