ラボ > Laravel、Lumen:ユーザー認証関連

Laravel8 ユーザー認証を自作(Auth Facades)

「Breeze」「Jetstream」「Fortify」のいずれかを使うのが基本らしいがカスタマイズするための学習コストが高すぎる…と思う

作成日:2022-12-27, 更新日:2023-01-05

基本

▼私の環境
WIN+Docker+Ubuntuでlaravelを使うための作業メモ

やりたいこと

ひとまず羅列

  • ログインしている・していない人で振分け
  • ログイン周り(ログインする、チェックする、ログアウト)
  • 自身のユーザー情報取得
  • 一般ユーザーと管理者を分けたい
  • ユーザー自身によるユーザー作成
  • 管理者によるユーザー作成
  • パスワードリマインダー
  • ユーザー自身によるユーザー情報の編集
  • 管理者によるユーザー情報の編集

ひとまず重要な項目

たぶん、この辺。

  • ログインしている・していない人で振分け
  • ログイン周り(ログインする、チェックする、ログアウト)
  • 自身のユーザー情報取得
  • 一般ユーザーと管理者を分けたい

どうとでも出来そうな項目

しょせんDBからレコードを取得、追加・更新・削除あたりをすればいいんでしょ?ってことで重要視はしない

  • ユーザー自身によるユーザー作成
  • 管理者によるユーザー作成
  • パスワードリマインダー
  • ユーザー自身によるユーザー情報の表示・編集
  • 管理者によるユーザー情報の表示・編集

Auth Facades ?

基本、「Auth Facades」っていうのか…名称はよく分からんけどメソッドが用意されている。使えるものは使う

▼「Auth Facades」を使うとき、必要なuse。他にも色々と必要っぽい

use Illuminate\Support\Facades\Auth;

※PATHは「vendor/laravel/framework/src/Illuminate/Support/Facades/Auth.php」になる

作業に入る前に…

Breezeってヤツを使えるようにしていたのでその削除
運が良いというか悪いといか…Breezeをインストールする前の状態があったので差戻し
→「composer remove」でアンインストールが出来るらしいけど、未調査

▼「コマンド: artisan」でエラーになる可能性が高いのでcomposerを実行

$ composer dump-autoload

エラー

あとでマイグレーションファイルを作成するのにartisanを実行したらエラーになった

   Error

  Class "Laravel\Breeze\BreezeServiceProvider" not found

  at vendor/laravel/framework/src/Illuminate/Foundation/Application.php:825

ログインしている・していない人で振分け

すでに関係のあるテーブルなどがあるのですることはひとまず少ない

  • ルーティング
  • コントローラ作成

※本来ならビューとかも作るけど、ただの確認用なのでコレだけ

ルーティング

▼「routes/web.php」に追加

Route::middleware('guest')->group(function () { // ログインしていないとき
    Route::get('/login', [Controllers\Auth\AuthenticatedSessionController::class, 'login'])->name('login'); // 「name('login')」がログインしていないときの飛ばし先の設定になる
});

Route::middleware('auth')->group(function () { // ログインしているとき
    Route::get('/profile', [Controllers\Auth\ProfileController::class, 'detail']);
});

ログインしていないとき

「app/Http/Middleware/Authenticate.php」の「redirectTo()」の「return route('login');」が上記の「name('login')」ってヤツと紐づく
なので、「return route('login');」のトコを好き勝手すればログインページ以外にも飛ばすことが可能

コントローラ作成

▼artisanコマンド実行

$ ./vendor/bin/sail php artisan make:controller Auth/AuthenticatedSessionController
$ ./vendor/bin/sail php artisan make:controller Auth/ProfileController

ひとまず中身は適当。__LINE__とかでもechoすればOK。
ブラウザから「login」と「profile」のそれぞれにアクセスして「Auth/AuthenticatedSessionController」の「login()」に入ってくれれば成功

ログイン周り(ログインする、チェックする、ログアウト)

ログインチェックはLaravelがどっかでやってくれているっぽい(※たぶんコイツ → 「app/Http/Middleware/Authenticate.php」)

ダミーデータ追加+ログイン+ログイン後のページにリダイレクト

まずダミーデータを追加(シーダーってヤツを使えばいいんだろうけど、確認のためだけに用意するのが面倒なんで適当なコントローラでユーザー作成)

▼useするヤツら

use App\Providers\RouteServiceProvider; // ログイン時の飛ばし先
use App\Models\User;
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash; // パスワードの作成関連

▼ダミーデータ追加+ログイン+ログイン後のページにリダイレクト

// ユーザー作成
$user = User::create([
    'name' => 'xxxx',
    'email' => 'xxxx@example.com',
    'password' => Hash::make('xxxxxx'),
]);

// ログイン処理
event(new Registered($user));
Auth::login($user);

// ログイン後のリダイレクト
return redirect(RouteServiceProvider::HOME); // 「App\Providers\RouteServiceProvider」の「HOME」が飛ばし先

ログイン

$credentials = $request->only('email', 'password');
// $credentials = $request->only('name', 'password'); // 「name」のほうを使うとき
if ( !Auth::attempt($credentials)) {
    // 認証失敗
}
$request->session()->regenerate();
return redirect()->intended(RouteServiceProvider::HOME);

ログアウト

Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');

自身のユーザー情報取得

▼こんな感じで取得可能(「use Illuminate\Support\Facades\Auth;」もいる)

$self = Auth::user();

ビューでログイン中か確認

@auth
    ログインしている人
@endauth

@guest
    ログインしていない人
@endguest

一般ユーザーと管理者を分けたい

一般ユーザーと管理者を分けるってのが何気に面倒っぽい

▼考えなくちゃいけないこと

  • 一般ユーザーと管理者の条件分岐させるデータ
  • ルーティング
  • 他、諸々

一般ユーザーと管理者の条件分岐させるデータ

私の環境だとすでに「テーブル: users」ってのがいる。
そのため「テーブル: users」に「カラム: usergroup」みたいな感じで追加、その値で「管理者・一般ユーザー、その他」で色々と分岐させるコトにする

マイグレーションファイル作成

$ ./vendor/bin/sail php artisan make:migration add_usergroup_on_user_table --table=users

→「database/migrations/2022_12_27_164445_add_usergroup_on_user_table.php」が作られた

マイグレーションファイルの中身

▼「database/migrations/2022_12_27_164445_add_usergroup_on_user_table.php」

~ 省略 ~
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->smallInteger('usergroup')->unsigned()->after('remember_token'); // bool値でもいいけど後で欲が出てもいいように…small int
        });
    }

    ~ 省略 ~
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('usergroup');
        });
    }
    ~ 省略 ~

マイグレートの実行

$ ./vendor/bin/sail php artisan migrate

他の修正箇所

app/Providers/AuthServiceProvider.php

~ 省略 ~
use Illuminate\Support\Facades\Gate;
~ 省略 ~
    public function boot()
    {
        $this->registerPolicies();

        Gate::define('admin', function ($user) { // 「'admin'」はルーティングで使う値
            return $user->usergroup == xxx; // 管理者にしたい「users.usergroup」の値をセット
        });
    }
~ 省略 ~

ルーティング: routes/web.php

Route::group(['prefix' => 'admin', 'middleware' => ['auth', 'can:admin']], function () {
    Route::get('/', function () {
        return 'admin only';
    });
});

コントローラでログイン成功時の処理

~ ログイン処理 ~

if (Auth::User()->usergroup == xxx) { // 管理者にしたい「users.usergroup」の値で飛ばし先変更
    // 管理者のとき
}
else {
    // 管理者じゃないとき
}

ログインしていないときはログインページ、ログイン後に元のページへ

上記のままでOK

ルーティングの「Route::middleware('auth')」が勝手にやってくれる

ユーザーによって処理を分けたい

管理者をエラい人と下っ端に分けてみる

  • ルーティングで処理分岐
  • コントローラで処理分岐
  • ビューで処理分岐

身も蓋もないけど…コントローラやビューだったら素直にユーザー情報取得して好きにすれば良いと思う

下準備: app/Providers/AuthServiceProvider.php

▼useするヤツ

use Illuminate\Support\Facades\Gate;

▼boot()の中身

$this->registerPolicies();
Gate::define('admin', function ($user) { // ただの管理者
    return $user->usergroup == xxx;
});

Gate::define('superuser', function ($user) { // エラい管理者
    return $user->usergroup == xxx;
});

ルーティングで処理分岐

Route::middleware(['auth', 'can:superuser'])->group(function () { // エラい管理者がログインしているとき
    Route::get('/hogepiyo', [Controllers\Auth\HogeController::class, 'piyo']);
});

コントローラで処理分岐

▼useするヤツ

use Illuminate\Support\Facades\Gate;

▼処理の分岐

if ( Gate::allows('superuser') ) {
    // エラ管理者
}

Gateの中身

  • Gate::allows() - 指定された一つの権限を持っている
  • Gate::check() - 指定された複数の権限(配列指定)をすべて持っている
  • Gate::any() - 指定された複数の権限(配列指定)のうち、少なくとも一つ持っている

※他は「vendor/laravel/framework/src/Illuminate/Support/Facades/Gate.php」を確認

ビューで処理分岐

素直にコントローラで処理分岐用のフラグを追加するのが無難

未調査

▼こんな感じで出来るとかあるけど…設定を色々とする必要があるっぽい

@can('update', $post)
    <!-- 現在のユーザーは投稿を更新可能 -->
@elsecan('create', App\Models\Post::class)
    <!-- 現在のユーザーは新しい投稿を作成不可能 -->
@else
    <!-- ... -->
@endcan

コントローラからビューへ自身のデータを渡す

$viewData = array(
    'user' => Auth::user()->toArray(), // 配列にして渡すのが個人的にラク
);
return view('hoge', $viewData);