Webエンジニアの日常とリーグオブレジェンド

Webエンジニアとして働いている猫のブログ。EmacsとMySQLとリーグオブレジェンド(LoL)が好物。主に技術的な記事かLoLの記事を書く。

PHP Laravel 標準の AuthenticatesUsers によるログインの処理を見てみる

f:id:yoshiki_utakata:20190622101834p:plain

環境

  • PHP 7.3
  • Laravel 5.8

はじめに

Laravel では標準で認証の機能がついている。デフォルトではメールアドレスとパスワードを利用してログインする。フォームにメールアドレスとパスワードを入力して送信すると、 LoginController::login メソッドにリクエストが送られる。

LoginController の中では use AuthenticatesUsers されており、この AuthenticatesUsers トレイとの login メソッドが呼ばれる仕組みになっている。

この login メソッドの中ではログイン試行回数のカウントや、Userテーブルとの照らし合わせなどさまざまなことをやっているが、このログイン周りの機能を独自に修正したい場合には、中身を知っておく必要があるので、中身を細かく見ていってみる。

AuthenticatesUsers::login の中でやっていること

framework/AuthenticatesUsers.php at 5.8 · laravel/framework · GitHub

以下のことをやっている

  • $this->validateLogin($request);
  • ログイン試行回数チェック( $this->hasTooManyLoginAttempts あたり)
  • $this->attemptLogin($request)
  • $this->incrementLoginAttempts($request);
  • return $this->sendFailedLoginResponse($request);

validateLogin

これの中身は単に $request->validate で、ログインに必要なパラメータが送られてきているかどうかを確かめているだけである。

hasTooManyLoginAttempts まわり

<?php

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

この一連の処理は、ログイン試行回数超過によりアカウントをロックする処理が書かれている。

hasTooManyLoginAttempts メソッドが定義されていると、このメソッドが呼ばれる。このメソッドでログイン回数が超過されていると判定された場合は fireLockoutEvent でアカウントロックを発動させ、 sendLockoutResponse を返す。

hasTooManyLoginAttemptsfireLocktoutEventThrottlesLogins というトレイトに実装されており、デフォルトだとこれが使われる。

ThrottlesLogins::hasTooManyLoginAttempts

RateLimiter

framework/RateLimiter.php at 5.8 · laravel/framework · GitHub

Cache(Chacheの中身は.envの設定次第)を利用し、デフォルトでは1分間に5回試行があるとアカウントが1分ロックされるようになっている。

この設定は $this->maxAttempts$this->decayMinutes をコントローラーなどに設定すると変更でき、 decayMinutes 分に maxAttempts 回 ログインに失敗すると decayMinutes 分ログインがロックされるという仕組みになっている。

attemptLogin

つづいて $this->attemptLogin でログインしようと試みる。ログインに成功すると sendLoginResponse される。

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

attemptLogin の中は以下のようになっている。

<?php
    protected function attemptLogin(Request $request)
    {
        return $this->guard()->attempt(
            $this->credentials($request), $request->filled('remember')
        );
    }

そして guard() の中身はこうなっている

<?php
    protected function guard()
    {
        return Auth::guard();
    }

Auth::guard メソッドは auth.phpguards に設定と連携しており、例えば

return Auth::guard('api');

とすると、

<?php
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

のAPIが使われる。

引数に何も指定していない場合( Auth::guard() )は、 auth.phpdefaults という設定があると思うので、それが使われる。

<?php
    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

この場合 guardsweb がデフォルトで 利用される。(auth.phpの設定についてはここでは詳しく説明しません)

ここでログインが成功した場合は sendLoginResponse でログイン成功レスポンスが送られる。

sendLoginResponse の中では、セッションが作成され、ログイン失敗回数がリセットされ、ログイン成功のレスポンスが返される。

それ以降の処理

ログインに成功したときは上記で処理が終わるので、それ以降は、ログイン失敗時の処理である。

ログイン失敗時は incrementLoginAttempts でログイン失敗回数をカウントし、 sendFailedLoginResponse でログイン失敗レスポンスが送られる。

PHPフレームワーク Laravel入門

PHPフレームワーク Laravel入門