[Laravel7] Laravel標準の(Auth)で行っていることを調査する

カテゴリ: Laravel

Laravel7が標準で用意しているAuthでログインした時で行われていることを確認する。
(何度も同じことを調べるので、調べた結果をメモしておく)


GET /login


ログイン画面が表示される。
id/passを入力してLoginボタンをクリックするとPOST /loginがコールされる

POST /login

エントリポイント

ログイン認証処理で、routeを確認すると、LoginController@loginがコールされる

$ php artisan route:list
​
POST /login
    -> App\Http\Controllers\Auth\LoginController@login

App\Http\Controllers\Auth\LoginController

LoginControllerはAuthenticatesUsersをuseしている。このファイル自体にlogin()メソッドはないが、AuthenticatesUsers traitをuseしている。

<?php
​
namespace App\Http\Controllers\Auth;
​
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
​
class LoginController extends Controller
{
    use AuthenticatesUsers;
​
    protected $redirectTo = RouteServiceProvider::HOME;
​
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }
}

Illuminate\Foundation\Auth\AuthenticatesUsers

login()メソッドははtraitで実装されている。

trait AuthenticatesUsers
{
    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);
    }


最初に出てくるvalidateLogin()はrequestをチェックしているだけ

    protected function validateLogin(Request $request)
    {
        $request->validate([
            $this->username() => 'required|string',
            'password' => 'required|string',
        ]);
    }


attemptLogin()にログイン処理は記載されてる

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


​​
attempt()は、セッションに認証を持つ場合SessionGuard::attempt()がコールされる。

namespace Illuminate\Auth;
​
class SessionGuard implements StatefulGuard, SupportsBasicAuth
{
    public function attempt(array $credentials = [], $remember = false)
    {
        $this->fireAttemptEvent($credentials, $remember);
​
        $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
​
        // If an implementation of UserInterface was returned, we'll ask the provider
        // to validate the user against the given credentials, and if they are in
        // fact valid we'll log the users into the application and return true.
        if ($this->hasValidCredentials($user, $credentials)) {
            $this->login($user, $remember);
​
            return true;
        }
​
        // If the authentication attempt fails we will fire an event so that the user
        // may be notified of any suspicious attempts to access their account from
        // an unrecognized user. A developer may listen to this event as needed.
        $this->fireFailedEvent($user, $credentials);
​
        return false;
    }


cookieはlogin()の処理で保存している

class SessionGuard implements StatefulGuard, SupportsBasicAuth
    ...
​
    public function login(AuthenticatableContract $user, $remember = false)
    {
        $this->updateSession($user->getAuthIdentifier());
​
        // If the user should be permanently "remembered" by the application we will
        // queue a permanent cookie that contains the encrypted copy of the user
        // identifier. We will then decrypt this later to retrieve the users.
        if ($remember) {
            $this->ensureRememberTokenIsSet($user);
​
            $this->queueRecallerCookie($user);
        }
​
        // If we have an event dispatcher instance set we will fire an event so that
        // any listeners will hook into the authentication events and run actions
        // based on the login and logout events fired from the guard instances.
        $this->fireLoginEvent($user, $remember);
​
        $this->setUser($user);
    }


updateSession()でセッションを登録する。

    protected function updateSession($id)
    {
        $this->session->put($this->getName(), $id);
​
        $this->session->migrate(true);
    }


認証できたら、LoginController::redirectToで指定されたURLにリダイレクトする。(デフォルトではGET /homeがコールされる)


GET /home

エントリポイント

route:listをみると、GET /homeはHomeController@indexにマッピングされている

$ php artisan route:list
​
GET /home
    -> App\Http\Controllers\HomeController@index



HomeControllerはコンストラクタでauthのmiddlewareを実行する

class HomeController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }


このauthが何のクラスかは、app/Http/Kernel.phpで指定されている

    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class


Authenticate::handle()は以下の通り。handle()は、処理をauthenticate()に任せて終わり

namespace Illuminate\Auth\Middleware;
​
class Authenticate implements AuthenticatesRequests
{
    public function handle($request, Closure $next, ...$guards)
    {
        $this->authenticate($request, $guards);
        return $next($request);
    }


該当リクエストへのガードを取得してガードに認証を移譲する。ガードが空なら認証エラー

    protected function authenticate($request, array $guards)
    {
        if (empty($guards)) {
            $guards = [null];
        }
​
        foreach ($guards as $guard) {
            if ($this->auth->guard($guard)->check()) {
                return $this->auth->shouldUse($guard);
            }
        }
​
        $this->unauthenticated($request, $guards);
    }


ガードはconfig/auth.phpで指定されている。

例えば、$guards = ['web']だった時、$this->auth->guard($guard)は、Illuminate\Auth\SessionGuardを返す。
この対応ルールは、config/auth.phpで定義されている

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




SessionGuardは、check()を持っておらず、代わりにGuardHelpersトレイトをuseしている。

class SessionGuard implements StatefulGuard, SupportsBasicAuth
{
    use GuardHelpers, Macroable;
​


GuardHelpersは、$this->user()がnullを返さなければ認証OKとしている。

namespace Illuminate\Auth;
​
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\UserProvider;
​
/**
 * These methods are typically the same across all guards.
 */
trait GuardHelpers
{
    public function check()
    {
        return ! is_null($this->user());
    }
こちらもおススメ

コメントを残す

メールアドレスが公開されることはありません。