【認証機能の実装】Laravel+Vue.jsでのDB連携

はじめに

先日作成したこちらのプロジェクトを用いて認証機能について学んでいこうと思います。

【Axiosの実装】Laravel+Vue.jsでのDB連携

環境に関して

Laravel 6.8

PHP 7.3

Windows/XAMPP/MySQL

参考教材に関して

Laravel(+Vue.js)でSNS風Webサービスを作ろう!

こちらの教材を使いながら、認証機能をコマンドは使わずに実装していきます。

※教材フル活用しました。ありがとうございました!!

また、認証機能はVue.js側ではなくLaravel側で実装してみます。

ちょび
以前、TechpitさんのSPA教材を参考にVue.js側で認証機能の実装した際に、Laravel側の方が手間が少ない気がしたためです。

認証機能の実装

認証機能実装に伴う変更点

1.テーブルの修正

ユーザーに紐づくuser_idカラムの追加

2.ルーティングの修正

3.コントローラの確認と編集

主にredirect先の編集をします。

4.Blade側でビューを作成

前回生成したプロジェクトはレイアウトを一切意識しない作りにしていました。

ですが、今回はヘッダー、ナビゲーションバーを用いた仕様にしていきます。

5.アクションメソッドの編集

ここで投稿するユーザーと投稿を紐づけたDBのCRUD実装をしていきます。

1.テーブルの修正

カラムを追加する方法もありますが、今回はphpMyAdminが使えるのでGUIでテーブルを削除。

マイグレーションファイルも1から作り直しました。

php artisan make:migration create_todos_table

マイグレーションファイルを編集

Schema::create('todos', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->integer('user_id'); // add
    $table->string('todo'); // add
    $table->timestamps();
});

反映

php artisan migrate

Todoモデルにリレーションの追加 教材1-6を参考

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; // add
class Todo extends Model
{
    public function user(): BelongsTo // add
    {
        return $this->belongsTo('App\User'); // thisはTodoモデル自身を指す。
    }
}

上記でTodoクラスのインスタンスから紐づくUserクラスのリストを取得できる。

Userモデルを編集(users.id と todos.user_id を紐付ける)

public function todos(){
    return $this->hasMany('App\Todo');
}

上記でUserクラスのインスタンスから紐づくTodoクラスのリストを取得できる。

マイグレーションファイルでよく記載しているreferencesは、外部キー制約(他のテーブルのデータを参照して代入できる値を制限できる)でリレーションではない。

hasMany メソッドは引数を省略しています。省略せずに書くと以下の通りです。

$this->hasMany('App\Todo','user_id','id');

第一引数が関連するモデル名(名前空間も含む)、第二引数が関連するテーブルが持つ外部キーカラム名第三引数はモデルに hasMany が定義されている側のテーブルが持つ、外部キーに紐づけられたカラムの名前です。ただ第二引数と第三引数は今回のようにある決まりに沿っている場合は省略できます。その決まりとは、第二引数が テーブル名単数形_id で第三引数が id であることです。

参照:入門Laravelチュートリアル (4) ToDoアプリのタスク一覧表示機能を作る 

2.ルーティングの修正

web.phpへ追記

Auth::routes(); // add

ルーティングの確認

php artisan route:list
ちょび
Auth::routes();の1文でルーティングがとても増えました。Actionがクロージャ(無名関数)になっているのはapi.php内で処理を全て記述しているからですね。。。苦笑
補足
Nameの部分はLaravelのRoute関数で利用できる。以下、一例。

<form method="POST" action="{{ route('register') }}">

認証機能は諸々この書き方で実装できるので非常に便利ですね。

3.コントローラの確認と編集

認証系のコントローラはController/Authディレクトリにデフォルトで作成されています。

例えば、上記画像記載のregisterメソッドはコントローラ内ではなく RegistersUsersトレイトにメソッドが定義されている。(use トレイト名で使用)

showRegistrationFormメソッドではreturn view('auth.register')と記載されている。このメソッド内の定義に合わせてビューを作っていきます

ちょび
Validatorメソッドがコントローラ内にデフォルトで定義されていて、自動で呼び出されるのもとても便利ですね。※ーメッセージは別途作成が必要。その際は$errors変数を扱って実装する。(教材2-7参考)

redirectは全て’/’になるようにこのタイミングで軒並み編集。

4.Blade側でビューを作成

①全体用のビューを作成。 教材1-4を参考

views/app.blade.phpとnav.blade.phpを作成。

※コードは一旦教材のものをコピってます。

welcome.blade.phpを編集

@extends('app')
@section('title', 'ToDoアプリ')
@section('content')
@include('nav') 
<div id="app">
  <h2>TODOアプリ</h2>
  <h4>-Laravel×Vue.jsで作ってみた-</h4>
  <example-component />
</div>
@endsection

②ユーザー登録画面の作成 教材2-5を参考

views/auth/register.blade.phpを作成。

※コードは一旦教材のものをコピってます。

http://127.0.0.1:8000/registerへアクセス。

ちょび
正直Sassの勉強でCSSも1から作ろうかと思っていましたが、MDBootstrapのデザインが良すぎるので妥協したくなってきました。。。笑

また、Laravelではformタグ内で@csrfを記述する必要があるが、これはHTMLに変換されると以下のようになる。

<input type="hidden" name="_token" value="(ランダムな値)">

③ログアウト機能実装

nav.blade.phpを編集。(教材2-6を参考)

ちょび
formタグ内にbuttonタグを配置せずにidタグで紐づけて実装しているのは印象的でした。

5.アクションメソッドの編集

1の工程でUserモデルとTodoモデルのリレーションは済んでいますが、アクションの処理が編集できていないため登録ができません。

ですので、api.php編集してCRUDができるようにしていきます。(※今回は簡易アプリのためコントローラで実装していません。)

api.phpの編集(※まずはUserデータが取得できるか確認しました。)

Route::get('/',function(){
    $user = Auth::user();
    return $user
});

これで行けるかと思いきや取得できませんでした。。。

(めちゃくちゃ苦戦。。。)

ためしにAuth::user()が使えないのかをblade側で確認するため以下を記載。

ログイン中です:{{ Auth::user() }}

すると以下のようにHTMLで展開されるのを確認。Blade側では使えること確認できた。

ログイン中です:{"id":2,"name":"testtest","email":"testtest@gmail.com","email_verified_at":null,"created_at":"2020-04-21 10:59:13","updated_at":"2020-04-21 10:59:13"}

解決策

Kernel.phpを編集することで解決しました。LaravelのAPIはデフォルトだとセッションが利用できない仕様です。すっかり忘れていました。。。

ミドルウェアセッションが/app/Http/Kernel.phpの$middlewareGroupsのwebにしか設定されていなかったため、apiで取得できなかった様です。
ですので、webにある\Illuminate\Session\Middleware\StartSession::class,をグローバルのミドルウェアに置いてあげれば解決。
参照:LaravelでAuth::user()がnullを返す時の対処法
ちょび
上記記事参考にKernel.phpを弄ってみましたが、僕の場合はEncryptCookiesクラスを有効にしたところ取得できるようになりました。また、Controller側ではuse Auth;の記載をしないと表示できませんでしたが、api.php側では記載の必要がありませんでした。これはweb.php然り。不思議。。。 
補足
デフォルトではUserクラスが認証用のユーザーテーブルのモデルになっていて、Userモデルの以下の記載でAuth::user();など使用できるようにしている。

use Illuminate\Foundation\Auth\User as Authenticatable;

セッション保持の仕組みを理解した後は簡単でした。

取得

public function get(){
    return response()->json(Auth::user()->todos()->get());
}

追加

public function post(Request $request){
    $todo = new Todo();
    $todo->todo = $request->todo;
    $todo->user_id = Auth::id(); // 追加するためにユーザーIDも取得
    $todo->save();
    return response("OK", 200);
}

これで実装完了しました◎

完成品

動画

トップ画面

ログイン画面

メイン画面

おわりに

今回で認証機能の実装ができました。

やっとLaravel+Vueの仕組みがちゃんと理解できてきた気がします。

いよいよポートフォリオ制作に挑戦かなと思います。

気付き

メイン画面をログイン有無にかかわらず統一するとミドルウェアをあまり考慮しなくても済むことに気付いた。

Vue.jsでページ遷移せずにDBを弄る実装ができるようになると、ビューの作成も最小限に抑えることができるなと実感した。

・バリデーションは今回実装しなかったが、Laravel側もエラーメッセージの自作が必要。(また、認証以外はFormリクエストを作るのがベターな実装。)

・ログイン前も画面を同じにするなら、未ログインユーザーに対してはLocalStorageのお試し実装もありかなと思った。(ビューは分ける必要あり??)
動画を再生させて疑似体験してもらえればいいんじゃない??と思い実装してみた。Videoタグなるものを知って感動。

参考

公式

validation.php言語ファイル – Laravel公式

Qiitaなど

【Laravel】1対多のテーブルリレーション・hasMany/belongsToとは?

リレーションの使い方の注意点 TP1-6

HEADメソッド【HTTPリクエストメソッド】

【videoタグ】HTMLで動画を埋め込む方法を徹底まとめ

コンストラクタでAuth::user()を取得する方法

【Laravel】既存テーブルで認証&認証方法を差し替えるTips

button要素のcssをリセットしたい

コメントを残す