Lesson 5

Laravelにおけるセキュリティ

Lesson 5 Chapter 1
認証

Lesson5ではセキュリティに関する学習を行なっていきましょう。今後の学習ではデータベースを使用していくことも増えていきます。その場合、重要な項目である「パスワードの管理方法」や「特定のユーザーのみ実行可能な処理」、「特定なユーザーのみ閲覧可能なページ」などを考慮する事で安全性の高いサービスを構築することができます。情報の漏洩などを防ぐために、セキュリティに対する考慮は開発者として必須スキルと認識しておく必要があります。

認証とは

認証とは、「ユーザーが誰」なのかを確認することです。区別したい部分は誰なのかという点になるので、今回はLaravelでログインの機能を実際に触れながら確認していきましょう。

ログイン機能の実装

Laravelではコマンドを入力することでログイン機能を実装することが可能です。以下コマンドを入力し、ログインの機能を作成してみましょう。

ログイン機能の実装

1. Laravel UIパッケージのインストール

ターミナル、コマンドプロンプト
composer require laravel/ui

2. 認証関連のファイル作成

ターミナル、コマンドプロンプト
php artisan ui vue --auth
実行結果
Please run [npm install && npm run dev] to compile your fresh scaffolding.

3. npm install && npm run devの実行

ターミナル、コマンドプロンプト
npm install
ターミナル、コマンドプロンプト
npm run dev

以上でログイン機能の実装は完了となります。

画面の確認

Laravelのウェルカムページ(http://127.0.0.1:8000/)へアクセスしてみましょう。ページ右上の位置にLogin・Registerが追加されていれば導入は完了です。

ログイン機能導入後のウェルカムページ

ログイン(Login)画面

ログイン画面

新規登録画面

新規登録画面

新規登録

ログインする為には新規登録を行う必要がありますが、現状では新規登録は行えません。新規登録を行うための準備を行いましょう。

テーブル(※詳細は今後のLessonで紹介致します。)

データを保存する為にはデータベースを作成し、作成したデータベース内にテーブルを作成する必要があります。今回はデフォルトで設定されているデータベース(Laravel)とユーザー情報を保存する為のusersテーブルの作成を行います。以下ディレクトリのファイルを開きましょう。

databases > migrations > (年)_(月)_(日)_000000_create_users_table.php

(年)_(月)_(日)_000000_create_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
};

こちらのファイルはLaravelをインストールした際に標準で用意されているテーブルになります。migrationファイルにテーブルの情報を記載しておくことでコマンドの実行によりテーブルが作成されます。例えば今後、新規登録をする際に電話番号や住所などの情報も登録させたい場合はこちらのcreate_users_table.phpファイルの中身を修正していくことで可能になります。

テーブル作成のコマンドを実行する

テーブルの作成はコマンド一つで作成が可能です。以下コマンドを実行しましょう。

ターミナル、コマンドプロンプト
php artisan migrate
実行結果
Running migrations.
  (年)_(月)_(日)_000000_create_users_table ..................................... 36ms DONE
  (年)_(月)_(日)_100000_create_password_resets_table ........................... 22ms DONE
  (年)_(月)_(日)_000000_create_failed_jobs_table ............................... 19ms DONE
  (年)_(月)_(日)_000001_create_personal_access_tokens_table .................... 25ms DONE
                      

標準で用意されている4つのファイル作成が完了しました。尚、今回使用するのはusersテーブルのみになります。

新規登録をする

新規登録を行う準備が完了しましたので、新規登録(Register)へアクセスし項目を入力して登録を行ってみましょう。

新規登録画面

新規登録完了画面

このように表示されていれば新規登録と同時にログインも完了になります。ページ右上には登録した際の名前が表示されていることも確認できます。ログアウトや再ログインも実行が可能となっておりますので、そちらも併せてご確認ください。

認証機能導入後の変化

簡単に導入前と導入後に起きた変化を確認していきましょう。

①web.php

routes > web.php

web.php
<?php
Auth::routes();

Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');

web.phpはこちらの2行が追加されています。Auth::routes()の部分は認証に関する処理やページを表示するルーティングが含まれています。2行目の部分はログイン後に表するページのルーティングになります。

②blade.php

bladeファイルは以下8種類のblade.phpが作成されています。

①resources > views > home.blade.php

 ログイン後のページを作成しているblade.php

home画面

②resources > views > login.blade.php

 ログインフォームを作成しているblade.php

ログインフォーム画面

③resources > views > register.blade.php

 登録フォームを作成しているblade.php

登録フォーム画面

④resources > views > verify.blade.php

 登録時に送信されるメールを作成しているblade.php

登録時に送信されるメール画面

⑤resources > views > passwords > confirm.blade.php

 パスワード再確認用のページを作成しているblade.php

パスワード再確認画面

⑥resources > views > passwords > reset.blade.php

 パスワード再設定用のメールを送信するblade.php

パスワード設定画面送信

⑦resources > views > passwords > email.blade.php

 パスワード再設定用のページを作成しているblade.php

パスワード再設定画面

⑧resources > layouts > app.blade.php

 ヘッダーを作成している共通用のblade.php

共通レイアウト

③controlle.php

以下Controllerの追加により各ページに表示が行われています。

①app > Http > Controllers > HomeController.php

 ログイン後のページを表示する処理が記載されたController.php

②app > Http > Controllers > Auth > ConfirmPasswordController.php

 パスワード再確認用のページを表示する処理が記載されたController.php

③app > Http > Controllers > Auth > ForgotPasswordController.php

 パスワード再設定用のメール送信処理とページを表示する処理が記載されたController.php

④app > Http > Controllers > Auth > LoginController.php

 ログイン、ログアウトの処理、ログイン用のページを表示する処理が記載されたController.php

⑤app > Http > Controllers > Auth > RegisterController.php

 新規登録の処理、新規登録用のページを表示する処理が記載されたController.php

⑥app > Http > Controllers > Auth > ResetPasswordController.php

 パスワード再設定用の処理とページを表示する処理が記載されたController.php

⑦app > Http > Controllers > Auth > VerificationController.php

 登録後のメール送信に関する処理が記載されたController.php

いかがでしたでしょうか。冒頭で行ったコマンド操作で上記ファイルが作成され、ログイン周りの処理を簡単に作成することができました。Laravelで開発するサービスの多くがログイン機能を備えたサービスになりますので、認証について把握しておきましょう。

Lesson 5 Chapter 2
認可

chapter2では認可について学習していきましょう。

認可とは

認可とはページの表示やデータの作成、削除、更新などの機能を特定のユーザーのみ許可することを指し、認可の設定をしておくことで、セキュリティ面での向上が可能になります。例えばサービス内で課金しているユーザーのみ閲覧可能なページ・利用可能な機能などを思い浮かべるとイメージが湧きやすいかもしれません。認可には「Gate」と「Policy」というアクションが用意されているので、それぞれ確認していきましょう。尚、今回の項目は今後学習する要素が含まれている為、実践ではなく動作確認を交えてご紹介します。

環境の確認

以下が今回の項目で使用していくページとデータベースになります。参考までにご確認ください。

ユーザーリスト

ユーザーリスト

使用するデータベース

usersテーブル

ユーザーリスト

booksテーブル(※Policyで使用)

小説リスト

Gate 準備と動作確認

それではまず初めにGateについて紹介を行なっていきます。Gateとは部分的に制限を設けることができるのが特徴です。今回はログインユーザーの権限が管理者(admin)であれば「編集」「削除」ボタンを表示させ、一般(general)であれば非表示になるよう制限を設けていきます。以下が修正するファイルになります。

①AuthServiceProvider.phpへGateの登録

app > Providers > AuthServiceProvider.php

AuthServiceProvider.php
<?php
namespace App\Providers;

use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The model to policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        // 'App\Models\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        // 追加
        Gate::define('AdminUser', function ($user) {
          return $user->role == 'admin';
        });

    }
}

Gateファサードの第一引数には、認可の際に使用する任意の名前を入れます。こちらは後ほど使用します。returnの部分でユーザーの権限がadminであればtrueを返し、adminでなければfalseを返す処理となっています。

②-1 blade.php内で認可を行う場合

test.blade.php

{{ -- 省略 -- }}
@foreach($users as $user)

<div class="flex">

    <div class="flex">
        <p>{{$user->name}}</p>
        <p>{{$user->email}}</p>
        <p>{{$user->role == "admin" ? "管理者" : "一般"}}</p>
    </div>

    @can("AdminUser")
    <div class="flex">
        <p><input type="submit" value="編集"></p>
        <p><input type="submit" value="削除"></p>
    </div>
    @endcan

</div>

@endforeach
{{ -- 省略 -- }}

ページ上で認可を行う場合は@canディレクティブを使用します。引数には先ほどAuthServiceProviderのGateファサードの第一引数に指定した名前を入れてあげることでボタンの出し分けが可能です。

管理者(admin)の画面

管理者画面

一般(general)の画面

管理者画面

②-2 Controller.php内で認可を行う場合

Controllerで認可を行う場合は主に「authorize」「allows」「denies」メソッドを使用します。

1. authorizeメソッド

authorizeメソッドは以下のように使用します。管理者であればGate::authorize以降の処理が実行され、管理者以外であれば403のページへと遷移されます。

TestController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

class TestController extends Controller
{
    public function test()
    {
      // authorizeメソッド
      Gate::authorize("AdminUser");

      $users = User::get();

      return view('home', compact("users"));
    }
}

管理者(admin)の画面

管理者画面

一般(general)の画面

管理者画面

2. allowsメソッド

allowsメソッドは以下のように使用します。Gateと違い403のページには遷移しない為、自身で403画面への遷移を設定するか、任意のページへリダイレクトしてあげます。

TestController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

class TestController extends Controller
{
    public function test()
    {
      // 管理者でない場合は403ページへ。
      if(!Gate::allows("AdminUser")){
        abort(403);
      }

      $users = User::get();

      return view('home', compact("users"));
    }
}

管理者(admin)の画面

管理者画面

一般(general)の画面

管理者画面

3. deniesメソッド

deniesメソッドは以下のように使用します。allowsとの違いは判定を逆転させたメソッドになります。先ほどの記述のallowsの部分のみをdeniesに変更してみます。

TestController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;

class TestController extends Controller
{
    public function test()
    {
      // 管理者でない場合は403ページへ。
      if(!Gate::denies("AdminUser")){
        abort(403);
      }

      $users = User::get();

      return view('home', compact("users"));
    }
}

管理者(admin)の画面

管理者画面

一般(general)の画面

管理者画面

②-3 ルーティングで認可を行う場合

ルーティングで認可を行う場合は以下のようにミドルウェアを使用することで認可を設けることが可能です。

web.php
<?php

use Illuminate\Support\Facades\Route;

// 管理者のみアクセスが可能
Route::get('/home', [App\Http\Controllers\TestController::class, 'test'])->middleware("can:AdminUser");

又、一つのルーティングではなく複数のルーティングに対して認可を設ける場合はグループ化することで可能となります。

web.php
<?php

use Illuminate\Support\Facades\Route;

// 管理者のみアクセスが可能
Route::middleware("can:AdminUser")->group(function () {
    Route::get('/home', [App\Http\Controllers\TestController::class, 'test']);
    // 2つ目のルーティング
    // 3つ目のルーティング
});

以上がGateの主な使用方法になります。

Policy 準備と動作確認

続いてはPolicyについて紹介していきます。Gateはbladeやcontrollerなどに認可を設定したのに対し、Policyはモデルに対して認可を設けることが可能となります。モデルは今後の学習で詳細を学んでいきますが、データベースにアクセスし、データの作成や削除、更新などが行えるファイルを指します。

①Policyファイルの作成

今回は前提として特定のユーザーが本の編集、削除を行えるシステムを作成していきます。まずはPolicyファイルを作成します。又、今回は予め用意していたモデル、Book.phpと紐付けを行う為、「--model=book」としていますが、紐付けを行わない場合は不要な記述となります。

ターミナル、コマンドプロンプト
php artisan make:policy BookPolicy --model=Book

app > Policies > BookPolicy.php

BookPolicy.php
<?php

namespace App\Policies;

use App\Models\Book;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class BookPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can view any models.
     *
     * @param  \App\Models\User  $user
     * @return \Illuminate\Auth\Access\Response|bool
     */
    public function viewAny(User $user)
    {
        //
    }

    /**
     * Determine whether the user can view the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Book  $book
     * @return \Illuminate\Auth\Access\Response|bool
     */
    public function view(User $user, Book $book)
    {
        //
    }

    /**
     * Determine whether the user can create models.
     *
     * @param  \App\Models\User  $user
     * @return \Illuminate\Auth\Access\Response|bool
     */
    public function create(User $user)
    {
        //
    }

    /**
     * Determine whether the user can update the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Book  $book
     * @return \Illuminate\Auth\Access\Response|bool
     */
    public function update(User $user, Book $book)
    {
        //
    }

    /**
     * Determine whether the user can delete the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Book  $book
     * @return \Illuminate\Auth\Access\Response|bool
     */
    public function delete(User $user, Book $book)
    {
        //
    }

    /**
     * Determine whether the user can restore the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Book  $book
     * @return \Illuminate\Auth\Access\Response|bool
     */
    public function restore(User $user, Book $book)
    {
        //
    }

    /**
     * Determine whether the user can permanently delete the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Book  $book
     * @return \Illuminate\Auth\Access\Response|bool
     */
    public function forceDelete(User $user, Book $book)
    {
        //
    }
}

「--model=Book」のオプションを実行することで作成したPolicyファイルには「viewAny(全表示)」「view(詳細表示)」「create(作成)」「update(更新)」「delete(削除)」「restore(物理削除の解除)」「forceDelete(物理削除)」の7つのメソッドが自動的に追加されます。

②Policyの登録

Gateと同様、AuthServiceProvider.phpへPolicyファイルとBookモデルの登録を行います。

app > Providers > AuthServiceProvider.php

AuthServiceProvider.php
<?php
namespace App\Providers;

use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The model to policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        // 追加
        "App\Models\Book" => "App\Policies\BookPolicy",
    ];

    // 省略

}

「 "App\Models\Book" => "App\Policies\BookPolicy"」でBookモデルとBookPolicyファイルを登録しています。

③Policyファイルに認可の設定

Policyファイルに認可の設定を行なっていきます。尚、今回使用しないメソッド部分は省略してます。

app > Policies > BookPolicy.php

BookPolicy.php
<?php

namespace App\Policies;

use App\Models\Book;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class BookPolicy
{
    use HandlesAuthorization;

    // 省略

    /**
     * Determine whether the user can update the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Book  $book
     * @return \Illuminate\Auth\Access\Response|bool
     */
    public function update(User $user, Book $book)
    {
        // 追加
        return $user->id === $book->user_id;
    }

    /**
     * Determine whether the user can delete the model.
     *
     * @param  \App\Models\User  $user
     * @param  \App\Models\Book  $book
     * @return \Illuminate\Auth\Access\Response|bool
     */
    public function delete(User $user, Book $book)
    {
        // 追加
        return $user->id === $book->user_id;
    }

    // 省略

}

冒頭でもお伝えしましたが、今回は本の編集と削除の処理を特定のユーザーのみ実行可能とする為、該当する処理のメソッドに記述を追加しています。usersテーブルのidとbooksテーブルのuser_idが一致しているかどうかの判定を行い、一致していればtrue、していなければfalseを返します。

④Policyの実行確認

ここからはGateとさほど違いはありません。認可を行う場所へ記述の追加を行なっていきます。

1. authorizeメソッド

TestController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;
use App\Models\Book;
use Illuminate\Http\Request;

class TestController extends Controller
{
    public function update(Book $book){

        $this->authorize('update', $book);

        $book->update();

        return redirect('/home');
    }

    public function delete(Book $book)
    {

        $this->authorize('delete', $book);

        $book->delete();

        return redirect('/home');
    }
}

authorizeの第一引数にはBookPolicy内で定義している該当のメソッドを代入し、第二引数にはBookモデルの変数を代入しています。authorizeにより、本の編集時と削除時に、ログインユーザーと本の登録者が一致していない場合は403ページへ遷移するよう処理が実行されます。

2. canメソッド

TestController.php
<?php

namespace App\Http\Controllers;

use App\Models\User;
use App\Models\Book;
use Illuminate\Http\Request;

class TestController extends Controller
{
    public function update(Book $book){

        if (Auth::user()->can("update", $book)) {
            $book->update();
        } else {
            abort(403);
        }

        return redirect('/home');
    }

    public function delete(Book $book)
    {

        if(Auth::user()->can("delete", $book)){
            $book->delete();
        }else{
            abort(403);
        }

        return redirect('/home');
    }
}

canメソッドは上記のように使用します。authorizeメソッドと同じようにcanメソッドの第一引数にはBookPolicy内で定義している該当のメソッドを代入し、第二引数にはBookモデルの変数を代入しています。一致していればif内の処理が実行され、一致していない場合の処理をelse内に記述してあげましょう。

3. middleware

ルーティングにはmiddlewareとcanを使用することで認可の設定を行うことができます。

web.php
<?php
use Illuminate\Support\Facades\Route;

Route::put('/update', [App\Http\Controllers\TestController::class, 'update'])
->middleware('can:update, book');

Route::delete('/delete', [App\Http\Controllers\TestController::class, 'delete'])
->middleware('can:delete, book');

以上がPolicyの主な使用方法になります。

認可についてはGateとPolicyの2種類ご紹介しました。Laravelを使用した開発を行う場合、ほとんどのサービスに認可が設けられています。現場のルールに従い、いずれの方法でも開発が行えるよう認可の存在を認識しておきましょう。

Lesson 5 Chapter 3
ハッシュ

chapter3ではハッシュ(Hash)について学習していきます。

ハッシュ(Hash)とは

主にパスワードをデータベース上に登録させる処理で使用され、暗号化する機能になります。パスワードがハッシュ化されていない場合はセキュリティ面でも非常に危険で、逆にハッシュ化されている場合はシステムの管理者であっても参照することが出来ないほど厳重に管理することが可能です。

ハッシュ化されているパスワードの確認

実際にハッシュ化されたパスワードを目視で確認してみましょう。一名の適当なユーザーを登録し、その際入力したパスワードを覚えておいてください。

新規登録画面

続いてはデータベースを確認していきます。XAMPPのコントロールパネルから「Go to Application」をクリックします。

db確認

以下のような画面が表示されたら上記メニューバーの「phpMyAdmin」をクリックします。

db確認

ここでサイドバーに表示されている部分がデータベースになります。データベース「laravel」をクリックします。

db確認

laravel内に存在するテーブルが表示されます。テーブル「users」をクリックします。

db確認

先ほど登録したユーザーの確認ができました。

db確認

注目して頂きたい部分は画面中央に位置しているpasswordになります。登録時に入力したパスワードと異なる文字列が登録されていることを確認できます。これがハッシュ化(暗号化)です。

ハッシュ化の処理を確認

続いてはどのようにハッシュ化が行われているのかを確認していきます。以下ファイルを開きましょう。

app > Http > Controllers > Auth > RegisterController.php

RegisterController.php
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

class RegisterController extends Controller
{
    // 省略

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return \App\Models\User
     */
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
    }
}

登録の処理はこちらのRegisterController内にあるcreateメソッドで実行されています。1行追加しましょう。

RegisterController.php
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\Models\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;

class RegisterController extends Controller
{
    // 省略

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return \App\Models\User
     */
    protected function create(array $data)
    {
        // 追加
        dd($data["password"], Hash::make($data['password']));

        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
    }
}

$data["password"]がハッシュ化される前のデータ、Hash::make($data['password'])がハッシュ化された後のデータになります。一度ログアウトを行い、再度新規登録を実行してください。

出力結果
"testtest" // app/Http/Controllers/Auth/RegisterController.php:67

"$2y$10$S6umaagwz4AKnq7rZyq33eGcUZp.sx04rt.lXxeiWhPzQ2ouNEpSq" // app/Http/Controllers/Auth/RegisterController.php:67

testtestがハッシュ化される前のパスワードで、$2y$10$S6uma...がハッシュ化後のパスワードになります。このようにハッシュ化は「Hash::make(ハッシュ化したい文字列)」にて実行されていることが確認できました。

ログイン処理の確認

ハッシュ化されたパスワードでどのようにログインが行われているのかを確認していきます。尚、こちらのファイルを操作する機会はほとんどありませんので簡単に確認を行なっていきます。以下がログインに関する処理が書かれているファイルになります。

vendor > laravel > ui > auth-backend > AuthenticatesUsers.php

AuthenticatesUsers.php
<?php

namespace Illuminate\Foundation\Auth;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;

trait AuthenticatesUsers
{

    // 省略

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

        // If the class is using the ThrottlesLogins trait, we can automatically throttle
        // the login attempts for this application. We'll key this by the username and
        // the IP address of the client making these requests into this application.
        if (
            method_exists($this, 'hasTooManyLoginAttempts') &&
            $this->hasTooManyLoginAttempts($request)
        ) {
            $this->fireLockoutEvent($request);

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

        if ($this->attemptLogin($request)) {
            if ($request->hasSession()) {
                $request->session()->put('auth.password_confirmed_at', time());
            }

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

        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }
}
AuthenticatesUsers.php

if ($this->attemptLogin($request)) {
  if ($request->hasSession()) {
    $request->session()->put('auth.password_confirmed_at', time());
  }

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

ログインの処理はloginメソッド内にある上記の部分で処理が行われています。if ($this->attemptLogin($request))の部分で入力したパスワードと登録されている入力内容と登録内容が一致しているかの判定を行なっています。

AuthenticatesUsers.php

/**
* Attempt to log the user into the application.
*
* @param  \Illuminate\Http\Request  $request
* @return bool
*/

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

/**
* Get the needed authorization credentials from the request.
*
* @param  \Illuminate\Http\Request  $request
* @return array
*/
protected function credentials(Request $request)
{
  return $request->only($this->username(), 'password');
}

更に判定の中身を辿っていくと、attempt()メソッド内で行われていることが確認できます。attemptが定義されている場所を確認してみましょう。

vendor > laravel > framework > src > Illuminate > Auth > SessionGuard.php

SessionGuard.php

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;
}

ログインの機能について辿ってみました。実際こちらのファイルを操作したりすることは今後ほとんどないので、覚えておく必要はありません。興味がある方は調べてみてください。

ハッシュ化されたパスワードの判定

先ほど、ログインの機能については深掘りする必要はないと説明しました。その理由としてLaravelのログイン機能をデフォルトの状態で使用するか、1からログイン機能を作るかの2択がほとんどなケースとして多い為です。

パスワードの判定

ログイン機能を自作する場合の基本的なロジックは入力内容と登録内容が一致しているかどうかで、一致していればログイン後の画面へ、不一致であればログイン前の画面へ遷移させます。

入力内容と登録内容の判定方法
Auth::attempt(["email" => "Test@test.com", "password" => "testtest"])

このようにattemptメソッドの引数に今回のログイン情報であるメールアドレスとパスワード(ハッシュ前)を代入し、一致していればtrue、一致していなければfalseが返ります。以下は簡単なログイン機能の使用例になります。

入力内容と登録内容の判定方法

public function login(Request $request)
{
  if(Auth::attempt(["email" => $request->email, "password" => $request->password])){
    // 一致していればログイン画面へ
    return redirect("/home");
  }else{
    // 一致していない場合はログイン前画面へ
    return redirect("/login");
  }
}

ハッシュ化されたパスワードの判定もこのようにLaravelで用意されているattemptメソッドで実行してくれるため、容易に実装が可能となります。Laravelの開発に慣れてきたら、独自の認証機能作成にチャレンジしてみましょう。