13
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

LaravelにGoogle2FAを利用して2要素認証を実装する

Last updated at Posted at 2018-12-19

最近、Laravelを触っていて、2要素認証の機能を入れられないか調べてみたら、Google Authenticatorを利用した方法があったので、試してみた。
ライブラリは、google2faを利用。
実際の案件で使っていないので、実用化するにはもっと色々考慮しないといけないと思うけど、お試しということで。

前準備

前準備として、今回はLaravelの5.7を使ってここの手順で、基本的な認証機能を構築。

.env ファイルを環境に合わせて編集して、

php artisan make:auth
php artisan migrate

で認証機能を実装。

google2faの導入

google2faをcomposerでインストール

composer require pragmarx/google2fa

QRコードのライブラリをcomposerでインストール

QRコードを導入したいので、QRコードのライブラリBaconQrCodeもインストール

composer require bacon/bacon-qr-code

secret keyの登録

カラムの追加

マイグレーションファイルを作成して、usersテーブルにsecret key用のカラムを追加

php artisan make:migration add_column_g2fa_key_users_table --table=users

カラム名などはお好みで。down()は省略。

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->string('g2fa_key')->nullable(true);
    });
}

マイグレーション実行

php artisan migrate

Secret Keyの登録

今回は、ユーザー登録時にSecret Keyを登録するようにする。

app/User.php
class User extends Authenticatable
{
    protected $fillable = [
        'name', 'email', 'password', 'g2fa_key', // g2fa_keyを追加
    ];
}
app/Http/Controllers/Auth/RegisterController.php
use PragmaRX\Google2FA\Google2FA; // 追加

class RegisterController extends Controller
{
    protected function create(array $data)
    {
        // SecretKeyを生成
        $g2fa = new Google2FA();
        $key = $g2fa->generateSecretKey();
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
            'g2fa_key' => $key, // カラムに登録
        ]);
    }
}

http://{your domain}/register からユーザー登録して、g2fa_keyにキーが登録されていればOK。

QRコードの作成

homeにGoogle Authenticatorで読み取る用のQRコードを表示する。

app/Http/Controllers/HomeController.php

use Illuminate\Support\Facades\Auth; // 追加
use PragmaRX\Google2FA\Google2FA; // 追加

class HomeController extends Controller
{
    public function index()
    {
        $user = Auth::user();

        $g2fa = new Google2FA();

        // $g2fa->setAllowInsecureCallToGoogleApis(true);
        $qrUrl = $g2fa->getQRCodeGoogleUrl(
            config('app.name'),
            $user->email,
            $user->g2fa_key
        );
        return view('home', ['qr' => $qrUrl]);
    }
}

おそらくだけど、ローカル環境はSSL対応ではないので、$g2fa->setAllowInsecureCallToGoogleApis(true);を追加する必要がある。

resources/views/home.blade.php

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Dashboard</div>

                <div class="card-body">
                    @if (session('status'))
                        <div class="alert alert-success" role="alert">
                            {{ session('status') }}
                        </div>
                    @endif

                    <img src="{{ $qr }}"> {{-- 追加 --}}
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

QRコードが表示されるので、Google AuthenticatorアプリでQRを読み込む。

認証処理

ログイン画面側を作っていく

Viewの修正

ログインフォームに認証キーの追加。一部だけ抜粋。

resources/views/auth/login.blade.php
<div class="form-group row">
    <label for="secret_key" class="col-md-4 col-form-label text-md-right">{{ __('認証キー') }}</label>

    <div class="col-md-6">
        <input id="secret_key" type="text" class="form-control{{ $errors->has('secret_key') ? ' is-invalid' : '' }}" name="secret_key" value="{{ old('secret_key') }}" required>

        @if ($errors->has('secret_key'))
            <span class="invalid-feedback" role="alert">
                <strong>{{ $errors->first('secret_key') }}</strong>
            </span>
        @endif
    </div>
</div>

LoginControllerの修正

LoginControllerに2要素認証のログインロジックを追加。追加した部分だけ抜粋。

app/Http/Controllers/Auth/LoginController.php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use PragmaRX\Google2FA\Google2FA;

class LoginController extends Controller
{
    public function authenticate(Request $request)
    {

        $email = $request->input('email');
        $password = $request->input('password');
        $secretKey = $request->input('secret_key');

        $credentials = ['email' => $email, 'password' => $password];

        if (Auth::once($credentials)) {
            $user = Auth::user();
            if ($user->g2fa_key) {
                $g2fa = new Google2FA();
                if (!$g2fa->verifyKey($user->g2fa_key, $secretKey)) {
                    return redirect()->route('login');
                }
                Auth::attempt($credentials);
            }
            return redirect()->intended($this->redirectTo);
        }

        return redirect()->route('login');
    }
}

routerにログイン処理を追加

追加したメソッドでログイン処理を行うように、routerに下記を追加。

routes/web.php
Route::post('login', 'Auth\LoginController@authenticate');

あとは、ログイン画面でログイン情報とGoogle Authenticatorで発行された番号を入力してログインできればOK


今回は、2段階ではなく2要素認証という形で試してみた。
バリデーションエラーの時とか、2段階にしたい時とかもっと考慮すべきことはたくさんあると思うけど、参考までにということで。
Laravelが触り始めたばかりでよくわかってないので、ログイン処理もお作法的に良いかなどは疑問。
あとは、Google2FA for Laravelというのもあるらしい。

今回試したソースは、ここにアップしてます。


参考サイト

13
11
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
13
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?