🐘

Laravel入門6 Todoアプリ(認証機能)

に公開

記事一覧

  1. Laravel × Docker 最速環境構築
  2. Laravel 入門1 ページ追加
  3. Laravel入門2 bladeディレクティブ
  4. Laravel入門3 静的ファイル
  5. Laravel入門4 Request
  6. Laravel入門5 Todoアプリ(データベース)
  7. Laravel入門6 Todoアプリ(認証機能)
  8. Laravel入門7 Todoアプリ(CRUD)

認証機能

認証機能とは

ログインやサインアップ周りの機能

View

  1. 以下のファイルを作成
  • login/index.blade.php
  • sign_up/index.blade.php
  • task/index.blade.php
.
├── laravel_app
│   └── resources
│       └── views
│           ├── login
│           │   └── index.blade.php # ログインページ
│           ├── sign_up
│           │   └── index.blade.php # サインアップページ
│           └── task
│               └── index.blade.php # タスク一覧ページ(ログイン後)
├── mysql_data
├── docker-compose.yml
└── Dockerfile

  1. ファイルを記述
  • login/index.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>ログインページ</h1>
    {{-- 【重要】login.storeのルーティングは後で作成する --}}
    <form action={{ route("login.store") }} method="POST">
        {{-- フォームのメソッドがPOSTの場合は、csrfトークンを設定する必要がある --}}
        {{-- (@csrfと書くだけでOK) --}}
        @csrf
        <label for="email">メールアドレス</label>
        <input type="email" name="email">

        <label for="password">パスワード</label>
        <input type="password" name="password">

        <button type="submit">ログイン</button>
    </form>
</body>
</html>

  • sign_up/index.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>サインアップページ</h1>
    {{-- 【重要】sign_up.storeのルーティングは後で作成する --}}
    <form action={{ route('sign_up.store') }} method="POST">
        {{-- フォームのメソッドがPOSTの場合は、csrfトークンを設定する必要がある --}}
        {{-- (@csrfと書くだけでOK) --}}
        @csrf
        <label>名前</label>
        <input type="text" name="name">

        <label>メールアドレス</label>
        <input type="email" name="email">

        <label>パスワード</label>
        <input type="password" name="password">

        <label>パスワード確認</label>
        <input type="password" name="passwordConfirmation">

        <button type="submit">サインアップ</button>
    </form>
</body>
</html>

  • task/index.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>タスク一覧ページ</h1>
    {{-- 後の記事で記述 --}}
</body>
</html>

Controller

  1. 以下のファイルを作成
  • LoginController.php
  • SignUpController.php
  • TaskController.php

コンテナ内に入る

docker compose run app bash

コントローラー作成コマンドを実行

php artisan make:controller LoginController
php artisan make:controller SignUpController
php artisan make:controller TaskController

以下ファイルが生成されればOK

.
├── laravel_app
│   └── app
│       └── Http
│           └── Controllers
│               ├── LoginController.php # ログイン用
│               ├── SignUpController.php # サインアップ用
│               └── TaskController.php # タスク用
├── mysql_data
├── docker-compose.yml
└── Dockerfile
  1. ファイルを記述
  • LoginController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class LoginController extends Controller
{
    function index() {
        return view("login.index");
    }
}

  • SignUpController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SignUpController extends Controller
{
    function index() {
        return view("sign_up.index");
    }
}

  • TaskController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TaskController extends Controller
{
    function index() {
        return view("task.index");
    }
}

web.php

  1. web.phpを編集
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TopController;
use App\Http\Controllers\LoginController; # ログインコントローラー
use App\Http\Controllers\SignUpController; # サインアップコントローラー
use App\Http\Controllers\TaskController; # タスクコントローラー

Route::get('/', function () {
    return view('welcome');
});

Route::get('/top', [TopController::class, 'index'])->name("top");

// Route::prefix("共通のパス")->group(function() {
// prefixを使うと、共通のパスを持つルーティングをまとめることができる
Route::prefix('sign_up')->group(function () {
    // サインアップフォーム
    Route::get('/', [SignUpController::class, 'index'])->name("sign_up");
    // サインアップ処理
    Route::post('/', [SignUpController::class, 'store'])->name("sign_up.store");
});

Route::prefix('login')->group(function () {
    // ログインフォーム
    Route::get('/', [LoginController::class, 'index'])->name("login");
    // ログイン処理
    Route::post('/', [LoginController::class, 'store'])->name("login.store");
});

Route::prefix('task')->group(function () {
    // タスク一覧ページ
    Route::get('/', [TaskController::class, 'index'])->name("task");
});

サインアップ

  1. SignUpController.phpを編集
  • SignUpController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User; // Userモデルを使用する
use Illuminate\Support\Facades\Hash; // パスワードのハッシュ化

class SignUpController extends Controller
{
    // エラーを受け取るためにRequestを追加
    function index(Request $request) {
        $error = $request["error"];

        return view("sign_up.index", compact("error"));
    }

    function store(Request $request) {
        // それぞれの入力値を取得
        $name = $request["name"];
        $email = $request["email"];
        $password = $request["password"];
        $passwordConfirmation = $request["passwordConfirmation"];

        // パスワードが一致するかどうか
        if ($password !== $passwordConfirmation) {
            $error = "パスワードが一致しません";
            return view("sign_up.index", compact("error"));
        }

        // where('カラム名', 値) 絞り込み
        // exists() データが存在するかどうかtrue or falseを返す
        // メールアドレスが既に登録されているかどうか
        if (User::where('email', $email)->exists()) {
            $error = "既に登録されているメールアドレスです";
            return view("sign_up.index", compact("error"));
        }

        // create(連想配列) データを追加する
        $user = User::create([
            'name' => $name,
            'email' => $email,
            'password' => Hash::make($password), // パスワードをハッシュ化して保存
        ]);

        // auth()->login($user) ログイン処理
        auth()->login($user);

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

  1. sign_up/index.blade.phpを編集
  • sign_up/index.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>サインアップページ</h1>
    <form action={{ route('sign_up.store') }} method="POST">
        @csrf
        <label>名前</label>
        <input type="text" name="name">

        <label>メールアドレス</label>
        <input type="email" name="email">

        <label>パスワード</label>
        <input type="password" name="password">

        <label>パスワード確認</label>
        <input type="password" name="passwordConfirmation">

        <button type="submit">サインアップ</button>
    </form>

    {{-- エラーがある場合に表示する --}}
    @if ($error)
        <p>{{ $error }}</p>
    @endif
</body>
</html>

  1. http://localhost:8000/sign_upにアクセスしてサインアップ機能を確認

エラーのメッセージが表示されているかなども確認できるとGood

ログイン

  1. LoginController.phpを編集
  • LoginController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User; // Userモデルを使用
use Illuminate\Support\Facades\Hash; // ハッシュパスワードのチェックに使用

class LoginController extends Controller
{
    // エラーを受け取るためにRequestを追加
    function index(Request $request) {
        $error = $request["error"];

        return view("login.index", compact("error"));
    }

    function store(Request $request) {
        // それぞれの入力値を取得
        $email = $request["email"];
        $password = $request["password"];

        // emailで絞り込み
        $user = User::where('email', $email)->first();

        // ユーザーが存在しない場合 or パスワードが一致しない場合にエラーを返す
        // Hash::check()でパスワードのチェックを行える
        if (!$user || !Hash::check($password, $user->password)) {
            $error = "メールアドレスまたはパスワードが間違っています";
            return view('login.index', compact("error"));
        }

        // auth()->login($user) ログイン処理
        auth()->login($user);

        return redirect()->route("task");
    }
}

  1. login/index.blade.phpを編集
  • login/index.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>ログインページ</h1>
    <form action={{ route("login.store") }} method="POST">
        @csrf
        <label for="email">メールアドレス</label>
        <input type="email" name="email">

        <label for="password">パスワード</label>
        <input type="password" name="password">

        <button type="submit">ログイン</button>
    </form>

    {{-- エラーがある場合に表示する --}}
    @if ($error)
        <p>{{ $error }}</p>
    @endif
</body>
</html>

認可ルーティング

認可ルーティングとは

ログイン後にのみアクセス可能なルーティング
-> 未ログインユーザーがアクセスしようとすると、ログインページなどにリダイレクトされる

  • web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TopController;
use App\Http\Controllers\LoginController;
use App\Http\Controllers\SignUpController;
use App\Http\Controllers\TaskController;

Route::get('/', function () {
    return view('welcome');
});

Route::get('/top', [TopController::class, 'index'])->name("top");

Route::prefix('sign_up')->group(function () {
    Route::get('/', [SignUpController::class, 'index'])->name("sign_up");
    Route::post('/', [SignUpController::class, 'store'])->name("sign_up.store");
});

Route::prefix('login')->group(function () {
    Route::get('/', [LoginController::class, 'index'])->name("login");
    Route::post('/', [LoginController::class, 'store'])->name("login.store");
});

// `Route::middleware('auth')->group(function () {` 内に入れると認可ルーティングになる
Route::middleware('auth')->group(function () {
    Route::prefix('task')->group(function () {
        Route::get('/', [TaskController::class, 'index'])->name("task");
    });
});

Discussion