Laravelでログインに3回失敗したらリダイレクトする

Laravel

Laravelでログインに失敗して、ロックアウト判定した際に処理をしたいという要件があったので、認証処理をカスタマイズしてみました。
この記事ではLaravelで「3回ログインに失敗したらgoogleにリダイレクトする」という処理のコード載せて解説しています。

ロックアウトにする回数・分数とロックアウト時の処理は簡単に変更することが可能です。
この記事で確認してみてください。

今回確認したLaravelのバージョンは6になります。

ロックアウト時に処理をする

サンプルコードと解説を載せています。

サンプルコード

Laravelで認証処理を追加するとapp/Http/Controllers/Auth/LoginController.phpがログイン時に使用されるコントローラーになります。
コメントを省いたコードは下記のような感じです。

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

class LoginController extends Controller
{
    use AuthenticatesUsers;

    protected $maxAttempts = 2;
    protected $redirectTo = RouteServiceProvider::HOME;

    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    protected function sendLockoutResponse(Request $request)
    {
        $this->clearLoginAttempts($request);
        return redirect("https://google.com");
    }
}

追加したコードは$maxAttemptsフィールドとsendLockoutResponseメソッドです。

解説

$maxAttemptsはロックアウトにする回数です。

2回に設定しています。
このように設定しておくと、ログインに2回失敗してもロックアウトされませんが、3回目でロックアウトされます。

sendLockoutResponseメソッドはロックアウト時に処理されるメソッドです。
ここに処理を書くと、ロックアウト時に処理することができます。

ここで処理しているのは
まず$this->clearLoginAttempts($request);とやっています。
このメソッドはロックアウトされた状態をクリアしています。

その後にGoogleにリダイレクトしてみました。

これだけで3回間違えるとリダイレクトするという処理ができます。

今回の実装は1分間に3回間違えるとロックアウトされます。
1分間の箇所を変えるには$decayMinutesフィールド$maxAttemptsと同じように定義して、数値を入れておきます。
protected $decayMinutes = 3;と定義すると3分になって、「3分の間に3回間違えたら…」という感じになります。

ログインから追って、少し詳しい解説

ログイン処理から確認してみました…

ログイン時に動く処理は、上記のコードで書いているAutheticatesUsersトレイトに書いています。
その中の処理が下記にようになっています。

public function login(Request $request)
{
    $this->validateLogin($request);

    if (method_exists($this, 'hasTooManyLoginAttempts') &&
        $this->hasTooManyLoginAttempts($request)) {
        $this->fireLockoutEvent($request);

        return $this->sendLockoutResponse($request);
    }

    if ($this->attemptLogin($request)) {
        return $this->sendLoginResponse($request);
    }

    $this->incrementLoginAttempts($request);

    return $this->sendFailedLoginResponse($request);
}

回数の判定をしているのは、hasTooManyLoginAttemptsメソッドを呼んでいる箇所です。
このメソッドの中で$maxAttemptsに設定した値を使って判定しています。

失敗した回数はLaravelのCache機能で保持しています。
失敗した回数が$maxAttemptsより大きくなったらtrueが返ってきます。
trueが返ってきたら、ifの中を通りますね。

$this->fireLockoutEvent($request)はロックアウトイベントを発生させます。
その後に、リターンで$this->sendLockoutResponse($request);としています。

このsendLockoutResponseメソッドの処理をオーバーライドしてリダイレクトするようにしているといった感じです。

オーバーライドする元の処理は、AuthenticatesUsersの中でuseされている下記のファイルで定義されています。
vendor/laravel/framework/src/Illuminate/Foundation/Auth/ThrottlesLogins.php

オーバーライドする元のメソッドは下記のようになっています。

protected function sendLockoutResponse(Request $request)
{
    $seconds = $this->limiter()->availableIn(
        $this->throttleKey($request)
    );

    throw ValidationException::withMessages([
        $this->username() => [Lang::get('auth.throttle', [
            'seconds' => $seconds,
            'minutes' => ceil($seconds / 60),
        ])],
    ])->status(Response::HTTP_TOO_MANY_REQUESTS);
}

やっている内容は秒数を取得して、バリデーションエラーとしてメッセージをフロントに返しています。
返されるメッセージはデフォルトでは下記です。

Too many login attempts. Please try again in :seconds seconds.

これはresources/lang/en/auth.phpに定義されています。
:secondsの箇所に「~秒後にもう一度試してください」というメッセージの秒数が当てはまります。

終わりに

今回はログインでロックアウトした場合の処理をカスタマイズしてみました。
Auth/LoginController.phpにはあまり処理が書いていませんが、AuthenticatesUsersトレイトの方にログイン時の処理が色々書いています。

オーバーライドすることで、処理がカスタマイズできるように色々定義されています。
ログイン周りの処理をカスタマイズした場合にはこちらを一度確認してみてください。

コメント

タイトルとURLをコピーしました