LoginSignup
5
4

laravel ui 認証

Last updated at Posted at 2021-08-15

リファレンスサイト

Breaze認証

laravel Breeze 認証

作成するlaravelのui認証機能一覧

  1. ログイン機能
  2. パスワードのリセット機能
  3. Email Verification機能(登録されたメールの確認機能)
    1. メールの実在性の確認
    2. ログインかつメール認証済みのユーザだけを許可する認証ができる。
  4. password confirm機能(再度passwordの再確認を求める)

認証機能はuserとadminで別々に作成します。

larabelのインストール

$
laravel new laravel-multi-auth

ui認証機能のインストール

version3.4からjQueryがデフォルトで削除されました。
composer require laravel/ui:^3.3
bootstrapの他に・react・vueがあります。
php artisan ui bootstrap --auth
$
npm install && npm run dev
$
npm run dev

user認証を作成する

usersテーブを作成するだけ

データベースはsqlite

env
#データベースをmySqlからsqliteに変更
DB_CONNECTION=sqlite
# DB_CONNECTION=mysql
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=
  • database.sqliteファイル の作成
windows
type nul > database/database.sqlite
  • 環境変数にgitを通していたら windowsでもtoouchコマンドが使える。
mac
touch database/database.sqlite
usersテーブル
php artisan migrate

認証リンク
image.png
user登録画面
image.png
user登録するとusersテーブルにデータが登録されて
sql viewer
image.png
登録されたデータでログインできる。
image.png
リメンバーミーにチェックをいれる。セッションが切れても次回アクセス時自動でログインしてくれる。
image.png
セッション時間はデフォルトで2時間
リメンバーミーを設定すると5年

通常のセッションのためのクッキー ララジャパン

session時間
//config\app.php
   //session時間
    'lifetime' => env('SESSION_LIFETIME', 120),
         //env
               SESSION_LIFETIME=120
//config\session.php
   //ブラウザをクローズした時,sessionを(true:切る)(false:切らない)
    'expire_on_close' => false,

   //クッキーの名前
    'cookie' => 'laravel_session',

//remember meで延長される時間 5年 2628000分<-変更する時はこの数字を変更する

vendor\laravel\framework\src\Illuminate\Cookie\CookieJar.php
    public function forever($name, $value, $path = null, $domain = null, $secure = null, $httpOnly = true, $raw = false, $sameSite = null)
    {
        return $this->make($name, $value, 2628000, $path, $domain, $secure, $httpOnly, $raw, $sameSite);
    }

パスワードリセットを確認をする。(forget passwordリンク).

メール送信のための環境設定
googleメールを使用する。
3番めのカードの Google へのログイン  1,[googleの2段回認証プロセスをオンにする](https://myaccount.google.com/security) 2.同じサイトで、上をオンにするとアプリ パスワードの設定ができる。 ①アプリを選択->その他->②名前を入力->適当な名前 お使いのデバイスのアプリ パスワード 123456789 <-メールパスワードになる。 3. envファイルの設定
env
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=グーグルのメール
MAIL_PASSWORD=123456789
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=グーグルのメール(適当なメールでもOK,but必要null値はerrorになる)
MAIL_FROM_NAME="٩(♡ε♡ )۶of٩(♡ε♡ )۶"
**MailTrap**のダミーのSMTPサーバを使用する

リンクをクリックするとメールアドレスの入力フォームが表示される
resources\views\auth\passwords\email.blade.php
image.png
データベースにアドレスがなければエラーになる
image.png
あれば、メールを送信しましたとのアラートが表示される
image.png
送られてきたメールのリンクをクリックすると、
image.png
パスワードの再入力画面が表示される
resources\views\auth\passwords\reset.blade.php
image.png
パスワードが再設定されログインされる。
resources\views\home.blade.php
image.png

mail Verification機能

  • 非検証のメールから検証済みのメールへ変更する。

ユーザーモデルにimplements MustVerifyEmail を追記

app\Models\User.php
// class User extends Authenticatable
class User extends Authenticatable implements MustVerifyEmail

ユーザー登録時メールの確認も行う場合
[verify=>true]Auth::routes()に追加

routes\web.php
//Auth::routes()
Auth::routes(['verify' => true]);

登録が完了すると
image.png
普通にログインできる。
image.png
ただ、メールが送られてくるのでリンク先にアクセスすると。
image.png
メールの検証が完了する。テーブルに検証時間が入る。
image.png
メール検証済みのユーザーのみが許可されるルートを作成する。

web.php
Route::get('/test', function () {
    return 'メールは検証済みです。';
})->middleware(['verified']);

検証済みのユーザーがアクセスすると
image.png
未検証のユーザーがアクセスすると
リダイレクトされる。リンクをクリックすると。
image.png
未検証のメール宛にメールが送信される。
image.png
送られてきたメールのリンクにアクセスすると検証済みのメールになり、サイトに許可される。
image.png

password.confirm

  • ユーザのパスワードの再確認を求めるルート
web.php
//middleware(['auth', 'password.confirm'])をはってやる。必ずauthとセット
Route::get('/confirmed', function () {
    return 'パスワードの確認';
})->middleware(['auth', 'password.confirm']);

アクセスするとパスワードの再入力画面にリダイレクトされる。
image.png
確認されるとアクセスサイトにリダイレクトされる。
image.png
その他パスワードのリセットをすると、password_resetsテーブルにメールアドレスとトークンと時間が記録される。時間内にメールのリンクにアクセスすると、
image.png
パスワードのリセットが完了すると消去される。
image.png

マルチ認証を実装する

image.png

  • 修正1⃣
    • メールのviewsと宛先の修正。
  • 修正2⃣
    • ルートの修正
      • これは作成と同時に修正されるので修正は不要
  • 修正3⃣
    • viewsのリンクの宛先の修正
  • 修正4⃣
    • コントローラーでリターンするviewsを修正
  • 修正5⃣
    • ガードとモデルを修正する
  • 修正6⃣
    • ミドルウェアのリダイレクト先の修正

➀,➁,➂ guardとmodelを作成(コピペ)する

[図解] Laravel の認証周りのややこしいあれこれ。

  1. まず、2種類のログイン機構が存在するため、ガードを2つに分けます。
  2. それぞれのテーブルを管理するモデルが必要なためモデルも2つに分ける
    必然的に、ログイン対象のモデルを管理している「プロバイダ」も2つに分ける
  3. プロバイダーが分かれたため、パスワードのリセットも分ける。

認証を新たに追加する。

config\auth.php
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
//+provider+driver(session)がguardになる。
        'admin-web'=>[
            'driver' => 'session',
            'provider' => 'admins',
        ]
    ],

◎providerはmodelを組み込んでいるため、modelが異なると区分する必要がある。

config\auth.php
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
//+これがguardではなく、上のadmin-webがguardになる。
        'admins' => [
            'driver' => 'eloquent',
            'model' => App\Models\Admin::class,
        ],
    ],

◎パスワードリセットの設定もプロバイダーとセットになっているため、
                        区分する必要がある

config\auth.php
    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
//+ return Password::broker('admins');の時の名前
        'admins' => [
            //消去するプロバイダー
            'provider' => 'admins',
            'table' => 'password_resets',//テーブルを分ける場合はここを修正 'admin_password_resets'とかにする。
            //リセットパスワードメールの有効時間(分)
            'expire' => 60,//一時間
            'throttle' => 60,
        ],
    ],

感覚的にはプロバイダーのadminがguardだが、
実際はその上のガードドライバ(session)を含むadmin-webがguardになる。

Adminモデルとadminsテーブルを作成する

$
php artisan make:model Admin -mf
database\migrations\2022_02_04_100720_create_admins_table.php
//今回は機能をそのままコピペするため、usersテーブルをそのままコピペ。
    public function up()
    {
        Schema::create('admins', 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();
        });
    }
adminsテーブルを作成
php artisan migrate

認証系のAdminモデルはAuthenticatableを必ず継承して作成する。

app\Models\Admin.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;

//+
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

// class Admin extends Model
class Admin extends Authenticatable implements MustVerifyEmail
{
//+
    use HasApiTokens, HasFactory, Notifiable;
    protected $fillable = [
        'name',
        'email',
        'password',
    ];
    protected $hidden = [
        'password',
        'remember_token',
    ];
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

}

修正5⃣ メールのviewsと宛先の変更

Authenticatableを継承して作成するため、メールの返信先のリンクを変更する必要がある。
image.png

modelから送るメールを修正する。
返信先のアドレスをadminに変更する。
image.png

  1. パスワードのリセットメールの修正
  2. 検証メールの修正

1.パスワードのリセットメールの宛先を修正する

  • 送り先を adminsテーブルのユーザーに修正するため
php artisan make:notification ResetPasswordAdminNotification
app\Models\Admin.php
use App\Notifications\ResetPasswordAdminNotification;
---------------------
//リセットパスワードを送るメソッド
    public function sendPasswordResetNotification($token)
    {
   //作成したクラスに変更する 引数はtokenと返信先のルート(url)とresetPasswordConfig
        $this->notify(new ResetPasswordAdminNotification($token, 'admin.password.reset', 'admins'));
    }

ResetPasswordAdminNotificationを編集する。

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Auth\Notifications\ResetPassword;


// class ResetPasswordAdminNotification extends Notification
class ResetPasswordAdminNotification  extends ResetPassword //修正
{
    use Queueable;

    public $resetPasswordRoute;
    public $resetPasswordConfig;

    public function __construct($token, $resetPasswordRoute = null, $resetPasswordConfig = null)
    {
        parent::__construct($token);
        $this->resetPasswordRoute = $resetPasswordRoute;
        $this->resetPasswordConfig = $resetPasswordConfig;
    }

    //$notifiableはモデルが入っている。
    public function toMail($notifiable)
    {

        if (static::$toMailCallback) {
            return call_user_func(static::$toMailCallback, $notifiable, $this->token);
        }

        if (static::$createUrlCallback) {
            $url = call_user_func(static::$createUrlCallback, $notifiable, $this->token);
        } else {

            //これが返信用のアドレス。引数でルート名'admin.password.reset'を渡している。
            $url = route($this->resetPasswordRoute,[
                'token' => $this->token,
                'email' => $notifiable->getEmailForPasswordReset(),
            ]);
        }

        //メールの内容
        return (new MailMessage)
            ->subject('主題:パスワードリセットについてや')
            ->line('リクエスト要求があったらからメールをおくった')
            //返信用URLのactionボタン
            ->action('パスワード変更サイトへGO', $url)
            ->line("このパスワードの有効期限は".config('auth.passwords.admins.expire')."期間です")
            ->line('見覚えがなかったら無視してくれ。');
    }
}

2.検証メールの宛先の修正

php artisan make:notification VerifyEmailNotification
app\Models\Admin.php
//+
use App\Notifications\VerifyEmailNotification;

----

//+
    public function sendEmailVerificationNotification()
    {
// 引数は 返信用のリンクの Uri
        $this->notify(new VerifyEmailNotification('admin.verification.verify'));
    }
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\URL;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Config;
use Illuminate\Notifications\Messages\MailMessage;

// class VerifyEmailNotification extends Notification
class VerifyEmailNotification extends VerifyEmail //修正
{
    use Queueable;

    protected $verifyEmailRoute; //追記

    //引数でルートを渡している。$this->notify(new XXX($token, 'admin.password.reset', 'admins'))
    public function __construct(/*追記*/$verifyEmailRoute/*='admin.verification.verify'*/)
    {
        $this->verifyEmailRoute = $verifyEmailRoute; //追記
    }

    protected function verificationUrl($notifiable)
    {
// 時間制限付きのリンク の作成
        return URL::temporarySignedRoute(
            $this->verifyEmailRoute,
            Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
            [
                'id' => $notifiable->getKey(),
                'hash' => sha1($notifiable->getEmailForVerification()),
            ]
        );
    }
// 引数の$url には $this->verifyEmailRoute が 渡る。
    protected function buildMailMessage($url)
    {
        return (new MailMessage)
            ->subject('メールアドレスの確認')
            ->line('以下のボタンをクリックして、メールアドレスの確認をしてください。')
            ->action('メールアドレスの確認', $url)
            ->line('アカウントを作成されていない場合は、これ以上の操作は必要ありません。');
    }
}

Admin authのルートを作成する。

  • 修正は不要 - 修正2⃣ に該当する
routes\web.php
//uri,コントローラー,nameの重複をgroupで解消
Route::group(['prefix' => '/admin', 'namespace' => 'Admin', 'as' => 'admin.'], function () {

    Auth::routes(['verify' => true]);

});

Admin authのコントローラーとviewsを作成する

Admin authのControllerを作成する

  • AuthディレクトリをAdminディレクトリの下にコピー
windows
xcopy app\Http\Controllers\Auth app\Http\Controllers\Admin\Auth/e/i
  • homeコントローラーをAdminディレクトリの下にコピー
windows
copy app\Http\Controllers\HomeController.php app\Http\Controllers\Admin\HomeController.php

image.png

Admin authのviewsを作成する

  • authディレクトリをAdminディレクトリの下にコピー
windows
xcopy resources\views\auth resources\views\admin\auth/e/i
  • home.blade.phpをAdminディレクトリの下にコピー
windows
copy resources\views\home.blade.php resources\views\admin
  • welcome.blade.phpをAdminディレクトリの下にコピー
windows
copy resources\views\welcome.blade.php resources\views\admin
  • app.blade.phpのファイルをコピーしてファイル名をadmin_app.blade.phpに変更する
windows
copy resources\views\layouts\app.blade.php resources\views\layouts\admin_app.blade.php

image.png

Admin authのコントローラーとviewsのリンクの宛先を修正する。

Admin Authコントローラーを修正する。

  1. コントローラーの階層を変更したため、ネームスペースを変更する。
  2. リダイレクト先をroute('admin.home')に変更する
  3. veiwsをauthからAdmin/authに変更
  4. guradをwebからweb-adminに変更
  5. providerをusersからadminsに変更
  6. passwordsをusersからadminsに変更
  7. middlewareのリダイレクト先をAdmin/authへ変更。

1.階層を変更したため、ネームスペースを変更する。

Admin/Auth配下の全コントローラーファイル
// namespace App\Http\Controllers\Auth;
namespace App\Http\Controllers\Admin\Auth;
app\Http\Controllers\Admin\HomeController.php
// namespace App\Http\Controllers;
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller; //追記 

2.リダイレクト先をAdmin/authに変更する

Admin/Auth配下の全コントローラー
 protected $redirectTo = RouteServiceProvider::ADMIN_HOME;

RouteServiceProviderにADMIN_HOMEを追加

app\Providers\RouteServiceProvider.php
    //ついでに追加 laravel8対策 コントローラーをフル表記しなくてすむ。
    protected $namespace = 'App\Http\Controllers'; //追記

    public const HOME = '/home';
    public const ADMIN_HOME = '/admin/home';//追記

3.veiwsをauthからAdmin/authに変更
Admin/Auth/Controllerのreturn viewreturn view('auth.*')から
                    return veiw('admin.auth.*')に変更する
image.png
image.png
passwordの再確認を行うviewをAdmin/auth/*に変更する
password/confirm.blade.php

app\Http\Controllers\Admin\Auth\ConfirmPasswordController.php

    public function showConfirmForm()
    {
        return view('admin.auth.passwords.confirm');
    }

リセットパスワードのemailの再入力画面をAdmin/auth/*に変更する。
password/email.blade.php

app\Http\Controllers\Admin\Auth\ForgotPasswordController.php


    public function showLinkRequestForm()
    {
        return view('admin.auth.passwords.email');
    }

ログインフォームとログアウト後の遷移先ををAdmin/auth/*に変更する。
login.blade.php

app\Http\Controllers\Admin\Auth\LoginController.php
use Illuminate\Http\Request;//ファザードではない。
use Illuminate\Http\Response;


    //adminのログインフォームを表示
    public function showLoginForm()
    {
        return view('admin.auth.login');
    }

    //adminサイトを表示させる。ログアウトしたらurl('/admin')へリダイレクト
    protected function loggedOut(Request $request)
    {
        // $request->wantsJson()は、ヘッダーX-Requested-Withを必要とせずにaxiosクエリをチェックします。
        //($requext->ajax())
        return $request->wantsJson()
            ? new Response('', 204)
            : redirect('/admin');
    }

レジスター登録画面をAdmin/auth/*に変更する。
register.blade.php

app\Http\Controllers\Admin\Auth\RegisterController.php
    // return veiwを修正
    public function showRegistrationForm()
    {
        return view('admin.auth.register');
    }

リセットパスワードの返信先の画面をAdmin/auth/*に変更する。
password/reset.blade.php

app\Http\Controllers\Admin\Auth\ResetPasswordController.php
use Illuminate\Http\Request;

------
    //追記 return veiwの変更
    public function showResetForm(Request $request, $token = null)
    {
        return view('admin.auth.passwords.reset')->with(
            ['token' => $token, 'email' => $request->email]
        );
    }

検証メールの確認を求める画面をAdmin/auth/*に変更する。
verify.blade.php

app\Http\Controllers\Admin\Auth\VerificationController.php
use Illuminate\Http\Request;

------------

    //追記 return viewの変更
    public function show(Request $request)
    {
        return $request->user('admin-web')->hasVerifiedEmail()
                        ? redirect($this->redirectPath())
                        : view('admin.auth.verify');
    }

ホーム画面をAdmin/auth/*に変更する。
home.blade.php

app\Http\Controllers\Admin\HomeController.php
    public function index()
    {
        return view('admin.home');//修正
    }

guradをwebからweb-adminに変更

  1. providerをusersからadminsに変更
  2. passwordsをusersからadminsに変更
    Admin/Auth/Controller
    image.png
    web認証からadmin-web認証へ変更する

認証動作を伴うコントローラー

  • LoginController.php
  • RegisterController.php
  • ResetPasswordController.php

providerをusersからadminsに変更する

テーブルに登録動作を行うコントローラー

  • RegisterController.php

passwordsをusersからadminsに変更する
パスワードリセットを伴うコントローラー

  • ForgotPasswordController.php
  • ResetPasswordController.php
app\Http\Controllers\Admin\Auth\LoginController.php
use Illuminate\Support\Facades\Auth;

---------
    //認証(ガード)をwebからadmin-webに変更してやる。
    protected function guard()
    {
        return Auth::guard('admin-web');
    }
app\Http\Controllers\Admin\Auth\RegisterController.php
//+
use App\Models\Admin;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;

--------------

    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],
            // 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
//ユニークの参照先テーブルを変更
            'email' => ['required', 'string', 'email', 'max:255', 'unique:admins'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);
    }
 //登録先をAdminへ変更
    protected function create(array $data)
    {
        return Admin::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
            'api_token' => Str::random(80),
        ]);
    }

//認証はadmin-webに変更
    protected function guard()
    {
        return Auth::guard('admin-web');
    }
app\Http\Controllers\Admin\Auth\ResetPasswordController.php
//+
use Illuminate\Support\Facades\Auth;
------------

//認証はadmin-webに変更
    protected function guard()
    {
        return Auth::guard('admin-web');
    }

//パスワードリセットのpasswordsをusersからadminsに変更
//Adminモデルに変更される。
    public function broker()
    {
        return Password::broker('admins');
    }
app\Http\Controllers\Admin\Auth\ForgotPasswordController.php
use Illuminate\Support\Facades\Password;

--------
//パスワードリセットのpasswordsをusersからadminsに変更
    public function broker()
    {
        return Password::broker('admins');
    }

middlwareをwebからadmin-webへ変更する。

defaultのwebは省略されている。

  • middleware('auth')
    • 未ログイン中ににアクセスするとlogin画面にリダイレクトさせる。
  • middleware('guest')
    • ログイン中にアクセスするとhome画面にリダイレクトさせる。
middleware('auth')がはられたコントローラー
- ConfirmPasswordController.php
- VerificationController.php
- HomeController.php//忘れずに

         //$this->middleware('auth');
          $this->middleware('auth:admin-web');
middleware('guest')がはられたコントローラー
- LoginController.php
        // $this->middleware('guest')->except('logout');
        $this->middleware('guest:admin-web')->except('logout');

- RegisterController.php
        // $this->middleware('guest');
        $this->middleware('guest:admin-web');

middlewareのリダイレクト先を修正する

  • middlewareの設定はApp\Http\Kernel.phpに記述されている.
app\Http\Kernel.php
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    ];

よって

  • middleware('auth')
    app\Http\Middleware\Authenticate.php を修正する
  • middleware('guest')
    app\Http\Middleware\RedirectIfAuthenticated.php を修正する

middleware('auth') を修正する

app\Http\Middleware\Authenticate.php
<?php

namespace App\Http\Middleware;

use Illuminate\Auth\Middleware\Authenticate as Middleware;
use Illuminate\Auth\AuthenticationException;


class Authenticate extends Middleware
{

    //下で追加した引数を追加。
    //引数はmiddleware('auth:追記1,追記2,追記3,・・・')といくらでも追加できる。
    //protected function redirectTo($request)
    protected function redirectTo($request, $guards=null)
    {
        if (!$request->expectsJson()) {
            $guards = empty($guards) ? [null] : $guards;

            foreach ($guards as $guard) {
                if ($guard == 'admin-web') {
// リダイレクトするルートを返してやる。
                    return route('admin.login');
                }
            }
            return route('login');
        }
    }

//+
    function unauthenticated($request, array $guards)
    {
// 未認証なら スローされる。
        throw new AuthenticationException(
// 修正
// 'Unauthenticated.', $guards, $this->redirectTo($request)
            'Unauthenticated.',
            $guards,
//$this->redirectTo()関数の引数に array $gurdsを追記してやる。
            $this->redirectTo($request, $guards)
        );
    }
}

2.middleware('guest') を修正する

app\Http\Middleware\RedirectIfAuthenticated.php
<?php

namespace App\Http\Middleware;

use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class RedirectIfAuthenticated
{
    // $guardはmiddlewareの引数
    //->middleware(['guest:追記1,追記2,追記3']);今回は追記1だけなので、...$guardsから$guardに修正
    public function handle(Request $request, Closure $next, $guard = null/*...$guards*/)
    {
        //1個だけなので繰り返す必要もない。
        // $guards = empty($guards) ? [null] : $guards;
        // foreach ($guards as $guard) {
        //     if (Auth::guard($guard)->check()) {
        //         return redirect(RouteServiceProvider::HOME);
        //     }
        // }

//もうすでに認証ずみなら、拒否して各々にリダイレクトさせる。
        if (Auth::guard($guard)->check()) {
            switch ($guard) {
                case 'admin-web':
                    return redirect(RouteServiceProvider::ADMIN_HOME);
                default:
                    return redirect(RouteServiceProvider::HOME);
            }
        }
        return $next($request);
    }
}

その他、ミドルウェアを修正する。

3.middleware('verified')--検証済みのユーザーだけ許可

php artisan make:middleware EnsureEmailIsVerified
app\Http\Middleware\EnsureEmailIsVerified.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Redirect;

class EnsureEmailIsVerified
{
    //middleware(['verified:admin.verification.notice,admin-web'])
    //$redirectToRoute = 'admin.verification.notice', 
    //$guard = 'admin-web'
// $guard の追加
//public function handle($request, Closure $next, $redirectToRoute = null)
    public function handle($request, Closure $next, $redirectToRoute = null, $guard = null)
    {
        // if (! $request->user() ||
        // ($request->user() instanceof MustVerifyEmail &&
        // ! $request->user()->hasVerifiedEmail())) {
        if (
// $guard の追加
            !$request->user($guard) ||
            ($request->user($guard) instanceof MustVerifyEmail &&
                !$request->user($guard)->hasVerifiedEmail())
        ) {

            return $request->expectsJson()
                ? abort(403, 'Your email address is not verified.')
                : Redirect::route($redirectToRoute ?: 'verification.notice');
        }

        return $next($request);
    }
}
app\Http\Kernel.php
protected $routeMiddleware = [
-------------------------------------
    // 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    'verified' => \App\Http\Middleware\EnsureEmailIsVerified::class,
];

4.middleware('password.confirm)
引数にリダイレクトルートを設定するだけで修正する必要がない。

})->middleware(['auth:admin-web', 'password.confirm:admin.password.confirm']);

Admin authのviewsのリンクの宛先を修正する。

  • 修正3⃣にあたる。
    image.png

新たにルートを追加する

web.php
Route::group(['prefix' => '/admin', 'namespace' => 'Admin', 'as' => 'admin.'], function () {
//+
    Route::get('/', function () {
        return view('admin.welcome');
    })->name('welcome');

    Auth::routes(['verify' => true]);
//+
    Route::get('/home', [App\Http\Controllers\Admin\HomeController::class, 'index'])->name('home');
});
Admin配下の全bladeで実行
//検索
@extends('layouts.app
//置換
@extends('layouts.admin_app
Admin配下の全bladeで実行
//検索
route('
//置換
route('admin.
resources\views\Admin\welcome.blade.php
        @if (Route::has('login'))
        
{{-- @if (Route::has('login'))の中を置き換え--}}
            <div class="hidden fixed top-0 right-0 px-6 py-4 sm:block">
                @auth('admin-web')
                    <a href="{{ url('/admin/home') }}" class="text-sm text-gray-700 underline">Home</a>
                @else
                    <a href="{{ route('admin.login') }}" class="text-sm text-gray-700 underline">Log in</a>

                    @if (Route::has('register'))
                        <a href="{{ route('admin.register') }}" class="ml-4 text-sm text-gray-700 underline">Register</a>
                    @endif
                @endauth
                <a href="{{ url('/') }}" class="text-sm text-gray-700 underline" style="margin-left: 15px">User</a>
            </div>

        @endif
layouts.app_admin.blade.php
//検索
@guest
//置換
@guest('admin-web')
//検索
route('
//置換
route('admin.

ついでに、adminのリンクを追記

resources\views\welcome.blade.php
----- 
 @auth
  省略
 @endauth
//追記
 <a href="{{ url('/admin') }}" class="text-sm text-gray-700 underline" style="margin-left: 15px">Admin</a>

Adminユーザーの機能を確認する。

  1. ログイン機能
  2. パスワードのリセット機能
  3. Email Verification機能(登録されたメールの確認機能)
    1. メールの実在性の確認
    2. ログインかつメール認証済みのユーザだけを許可する認証ができる。
  4. password confirm機能(再度passwordの再確認を求める)

上記機能を確認するためのルートを作成する

routes\web.php
//uri,コントローラー,nameの重複を解消
Route::group(['prefix' => '/admin', 'namespace' => 'Admin', 'as' => 'admin.'], function () {
    Route::get('/', function () {
        return view('admin.welcome');
    })->name('welcome');
    Auth::routes(['verify' => true]);
 Route::get('/home', [App\Http\Controllers\Admin\HomeController::class, 'index'])->name('home');

//+
    //検証確認済みしかアクセスできないルート
    Route::get('/verified', function () {
        return 'あなたのメールは検証済みです。';
    })->middleware(['auth:admin-web','verified:admin.verification.notice,admin-web']);

    //パスワードの再確認がいるルート
    Route::get('/confirmed', function () {
        return 'パスワードが確認できました';
    })->middleware(['auth:admin-web', 'password.confirm:admin.password.confirm']);

});

route('admin.welcome')にアクセスすると、リンクが作成されている。
image.png
adminユーザー登録するとデータがadminsテーブルに登録される。
image.png
ログインしてミドルウェアを確認する。
route('admin.login')にアクセスする。
route('admin.home')に遷移される。
image.png
ログアウトするとroute('admin.welcome')に遷移される。
image.png
ログアウト中にroute('admin.home')へアクセスすると
route('admin.login')に遷移される。
image.png
route('admin.verified')にアクセスする
ログインアウト中ならroute('admin.login')に遷移
image.png
ログイン中+未検証なら。route('admin.email')に遷移される。
image.png
メールにアクセスするとroute('admin.verified')にアクセスできた。
image.png

middleware('verified:admin.verification.notice,admin-web')の
リダイレクト先を遷移前のルートに変更する。
デフォルトではログイン後route('admin.home');に遷移される。

app\Http\Middleware\EnsureEmailIsVerified.php
    public function handle($request, Closure $next, $redirectToRoute = null, $guard = null)
    {
        if (
            !$request->user($guard) ||
            ($request->user($guard) instanceof MustVerifyEmail &&
                !$request->user($guard)->hasVerifiedEmail())
        ) {

//+
    //追記 Session::pull('url.intended');コレが使えない(T_T)ためこんなことしてる。
            $path = $request->url();//追記
            session(['verified' => $path]);//追記
            
            return $request->expectsJson()
                ? abort(403, 'Your email address is not verified.')
                : Redirect::route($redirectToRoute ?: 'verification.notice');
        }

        return $next($request);
    }
app\Http\Controllers\Admin\Auth\VerificationController.php
    //ログイン後の遷移先
//+
    public function redirectPath()
    {
        session()->forget('url.intended');
        $path = session()->pull('verified');
        return  $path;
    }

webとadmin-webの情報を取得する場合

{{ dd(auth('web')->user(),auth('admin-web')->user()) }}

@Auth

Laravel メールをキューを使って送信する

①Userモデルのpasswordリセット、verificationメール
②Adminモデルのpasswordリセット、verificationメール
それぞれで実装する。
Userモデルのpasswordリセット、verificationメールをキュ~送信する。

envファイルでの設定。

QUEUE_CONNECTION=database
//queue送信時routeの生成で利用するため。
APP_URL=https://localhost/user_admin_auth/public

jobsテーブルのマイグレーションファイルを作成

php artisan queue:table

テーブルを作成する。

php artisan migrate

1.Userのメール送信をqueu送信する。
verificationメールをqueu送信.
メール機能を拡張する必要があるため、メールを作る

php artisan make:notification UserVerifyEmailNotification
app\Notifications\UserVerifyEmailNotification.php
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Auth\Notifications\VerifyEmail;//追記

class UserVerifyEmailNotification /*<修正>*/extends VerifyEmail implements ShouldQueue /*</修正>*/
{
    use Queueable;

    //以下削除

}
app\Models\User.php
use App\Notifications\UserVerifyEmailNotification;//追記

------------
    //追記
    public function sendEmailVerificationNotification()
    {
        $this->notify(new UserVerifyEmailNotification());
    }

passwordリセットをqueu送信する
手順は全く同じ。

php artisan make:notification UserResetPasswordEmailNotification
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

use Illuminate\Auth\Notifications\ResetPassword;

class UserResetPasswordEmailNotification /*<修正>*/extends ResetPassword implements ShouldQueue/*</修正>*/
{
    use Queueable;
}
app\Models\User.php
    public function sendPasswordResetNotification($token)
    {
        //引数は要,トークンとルート名とpasswords名
        $this->notify(new UserResetPasswordEmailNotification($token, 'password.reset', 'users'));
    }
php artisan queu:work

設定を確認する。

未検証のメールで登録して、動作が改善されているのを確認して送られてきたメールのリンクをクリックして検証を完了させる。

パスワードリセットにメールを送って、動作が改善されているのを確認して送られてきたメールのリンクをクリックしてパスワードをリセットする。

Adminのメールをqueu送信する。

これは既にメールを作成済みなので作成済みメールを修正する。

Adminのverificationメールをqueu送信.

app\Notifications\VerifyEmailNotification.php
use Illuminate\Contracts\Queue\ShouldQueue;//無ければ追加

class VerifyEmailNotification extends VerifyEmail /*<追記>*/implements ShouldQueue/*</追記>*/ 
{
    use Queueable;//コメントアウトしてたら解除

AdminのpasswordResetメールをqueu送信.

app\Notifications\ResetPasswordNotification.php
use Illuminate\Contracts\Queue\ShouldQueue;//無ければ追加

class ResetPasswordNotification  extends ResetPassword /*<追記>*/implements ShouldQueue/*</追記>*/
{
    use Queueable;//コメントアウトしてたら解除

一般ログインと管理ログインを同時にしている状態を防ぐ

user の ログインコントローラに、

app/Http/Controllers/Auth/LoginController.php
    public function __construct()								
    {
// web 認証していると logout メソッド以外のメソッドにはアクセスできなくなる。								
        $this->middleware('guest')->except('logout');		

// admin-web認証していると 全てのメソッドへのアクセスを拒否される。				
        $this->middleware('guest:admin-web');								
    }								

管理画面のルートとuser画面のルートでファイルを区分

  • RouteServiceProvider.phpでadminルートとuserルートを別々のファイルで管理させる。
    • 一般ユーザー用のfront.php
    • 管理画面用のback.php
app/Providers/RouteServiceProvider.php
    public const HOME = '/home';

 //追記
    protected $namespace = 'App\Http\Controllers';

//追記
    public const ADMIN_HOME = '/admin/home';

    public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::prefix('api')
                ->middleware('api')
                ->namespace($this->namespace)
                ->group(base_path('routes/api.php'));

//コメントアウト
            // Route::middleware('web')
            //     ->namespace($this->namespace)
            //     ->group(base_path('routes/web.php'));

// フロント画面 routes/front.php
            Route::middleware('web')
            ->namespace($this->namespace . '\Front')
            ->as('front.')
    //filepath+file名
            ->group(base_path('routes/front.php'));

// 管理画面 routes/back.php
           //admin/~
            Route::prefix('admin')
                ->middleware('web')
                //コントローラーのエイリアスを指定
                ->namespace($this->namespace . '\Back')
                ->as('back.')
    //filepath+file名
                ->group(base_path('routes/back.php'));
        });
    }

ルートでのコントローラーのエイリアスを省略したい場合は下記のコードを追加するだけでいい。

 //追記
    protected $namespace = 'App\Http\Controllers';

ログインに必要な項目を変更する

  • email から name に変更
app/Http/ Controllers/Auth/LoginController.php
// +
    public function username()
    {
        // return 'email';
        return 'name';
    }

ログインに必要な項目を追加する

簡単な方から。

active項目が1である条件を付加している。らしぃ。
リクエストでactiveを送信してusersテーブルからuserを取得できたらtrueになる。

laravel/app/Http/Controllers/Auth/LoginController
//credentials()をオーバーライド
protected function credentials(Request $request)
{
    $request->merge(['active' => 1]);
    
    return $request->only($this->username(), 'password', 'active');
}
  • 解説
    • SessionGuardインスタンスのattemptメソッド
PHP
// credentialsは['email'=>'xxx','password'=>'xxx','active'=>1]
  public function attempt(array $credentials = [], $remember = false)
  {
      $this->fireAttemptEvent($credentials, $remember);

// ここで DB から (emailとactive の値 が一致する) user を 取得 する。
      $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);

// 取得したuser の パスワードをチェックしてOKだったら
      if ($this->hasValidCredentials($user, $credentials)) {

// ログインして true を返す
          $this->login($user, $remember);

          return true;
      }
// パスワードチェックがfalseだったら false を 返す
      return false;
  }

複数テーブルを参照する等、少し複雑な認証をしたい場合

その他参照サイト


5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4