PHP
Laravel

Laravel5.8 認証Multi Auth(マルチログイン)(管理者・一般ユーザー)をお手軽に実装したときに、Auth::user()は管理者・一般ユーザーどっちの値をとるのか気になったので試してみた。


目的 Auth::user()を使うことなので、ログイン・ログアウト・登録の機能を実装する(管理者・一般ユーザー)


さくっとMulti Authを実装する

Laravel標準装備の認証機能を利用する

php artisan make:auth


管理者のmigrationファイルとModelを作成する。

php artisan make:model Admin -m

app配下にModelsディレクトリを用意し、その下にUser.phpとAdmin.phpを入れる

名前空間をnamespace App\Models;に修正する。

User.phpをAdmin.phpへコピー


Admin.php

<?php

namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;

class Admin extends Authenticatable
{
use Notifiable;

protected $fillable = [
'name', 'email', 'password',
];

protected $hidden = [
'password', 'remember_token',
];

protected $casts = [
'email_verified_at' => 'datetime',
];
}


もともと用意されているユーザー用のMigrationファイルの中身を管理者用のMigrationファイルへコピー

class CreateAdminsTable extends Migration

{
public function up()
{
Schema::create('admins', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}

public function down()
{
Schema::dropIfExists('admins');
}
}

テーブルを作成する

root@d8801ff1fed8:/var/www# php artisan migrate

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table
Migrating: 2019_06_11_125453_create_admins_table
Migrated: 2019_06_11_125453_create_admins_table


config/auth.php(認証設定)を変更する

//デフォルトではguardがwebになっており、webはusersをproviderとしているため、guard・guardsをusers・userに設定しなくてもいいが、見やすさを優先して、今回そうしている。

'defaults' => [
'guard' => 'user',
'passwords' => 'users',
],
'guards' => [
'user' => [
'driver' => 'session', //認証方法
'provider' => 'users', //providersの利用するもの
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],

'admins' => [
'driver' => 'eloquent', //認証へのアクセス方法
'model' => App\Models\Admin::class, //参照するテーブル
],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
'admins' => [
'provider' => 'admins',
'table' => 'password_resets', //参照するテーブル
'expire' => 60, //パスワードリセットの制限時間(分)
],
],

設定を変更したので、反映します。

php artisan config:cache


route/web.phpを定義する

php artisan make:authによって、Auth::routes();が作成されているので、これのもとを見てログイン・ログアウト・登録関連のルートをコピーして編集する。

vendor\framework\src\IlluminateRouting\Router.phpのauthメソッドにその記述があるので、参考にする。


vendor\framework\src\IlluminateRouting\Router.php

$this->get('login', 'Auth\LoginController@showLoginForm')->name('login');

$this->post('login', 'Auth\LoginController@login');
$this->post('logout', 'Auth\LoginController@logout')->name('logout');

// Registration Routes...
if ($options['register'] ?? true) {
$this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
$this->post('register', 'Auth\RegisterController@register');
}


上記を参考に


web.php

Auth::routes();

Route::group(['prefix' => 'admin'], function(){
Route::get('home', 'AdminHomeController@index')->name('admin_auth.home');
Route::get('login', 'AdminAuth\LoginController@showLoginForm')->name('admin_auth.login');
Route::post('login', 'AdminAuth\LoginController@login')->name('admin_auth.login');
Route::post('logout', 'AdminAuth\LoginController@logout')->name('admin_auth.logout');
Route::get('register', 'AdminAuth\RegisterController@showRegisterForm')->name('admin_auth.register');
Route::post('register', 'AdminAuth\RegisterController@register')->name('admin_auth.register');
});

Route::get('/home', 'HomeController@index')->name('home');


管理者用(Admin)にルートを作成した。


コントローラーの作成

先ほど作成したルートを元に作成していく。

HomeController.phpの中身をコピーして変更

Laravelのmiddlewareはコロン(:)で区切って、引数を指定できる。(今回はadmin)


AdminHomeController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Auth;

class AdminHomeController extends Controller
{
public function __construct()
{
$this->middleware('auth:admin');
}

public function index()
{
return view('admin_home');
}
}


Controllersディレクトリ配下にAuthAdminディレクトリを作成して、AuthのLoginController.phpとRegisterController.phpの中身をコピーして変更する


AdminAuth\LoginController

<?php

namespace App\Http\Controllers\AdminAuth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{
use AuthenticatesUsers;

protected $redirectTo = '/admin/home';

public function __construct()
{
$this->middleware('guest:admin')->except('logout');
}

public function showLoginForm()
{
return view('admin_auth.login');
}

protected function guard()
{
return Auth::guard('admin');
}

public function logout(Request $request)
{
$this->guard()->logout();
return redirect('/');
}
}



AdminAuth\ResisterController

<?php

namespace App\Http\Controllers\AdminAuth;

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

class RegisterController extends Controller
{
use RegistersUsers;

protected $redirectTo = '/admin/home';

public function __construct()
{
$this->middleware('guest:admin');
}

public function showRegisterForm()
{
return view('admin_auth.register');
}

protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:admins',
'password' => 'required|string|min:6|confirmed',
]);
}

protected function create(array $data)
{
return Admin::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}

protected function guard()
{
return Auth::guard('admin');
}

}



Viewを用意する

今回は、ユーザーは一通りそろっているので、管理者用にログインと登録画面を用意します。

views配下にadmin_authディレクトリを作成して、その下にauthディレクトリの中の、login.blade.phpとresister.blade.phpを、コピーして変更する。また、layout配下にadmin_app.blade.phpを作成し、views配下にadmin_home.blade.phpも作成します。ほぼコピーです。(基本的にルートだけ変える)


layouts/admin_app.blade.php

<!DOCTYPE html>

<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">

<title>{{ config('app.name', 'Laravel') }}</title>

<!-- Scripts -->
<script src="{{ asset('js/app.js') }}" defer></script>

<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">

<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
{{ config('app.name', 'Laravel') }}
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>

<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav mr-auto">

</ul>

<!-- Right Side Of Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Authentication Links -->
@guest
<li class="nav-item">
<a class="nav-link" href="{{ route('admin.login') }}">{{ __('Login') }}</a>
</li>
@if (Route::has('register'))
<li class="nav-item">
<a class="nav-link" href="{{ route('admin.register') }}">{{ __('Register') }}</a>
</li>
@endif
@else
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }} <span class="caret"></span>
</a>

<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('admin.logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Logout') }}
</a>

<form id="logout-form" action="{{ route('admin.logout') }}" method="POST" style="display: none;">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
</div>
</nav>

<main class="py-4">
@yield('content')
</main>
</div>
</body>
</html>



admin_auth/login.blade.php

@extends('layouts.admin_app')

@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Login') }}</div>

<div class="card-body">
<form method="POST" action="{{ route('admin.login') }}">
@csrf

<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>

@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">

@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="form-group row">
<div class="col-md-6 offset-md-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>

<label class="form-check-label" for="remember">
{{ __('Remember Me') }}
</label>
</div>
</div>
</div>

<div class="form-group row mb-0">
<div class="col-md-8 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Login') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection



admin_auth/resister.blade.php

@extends('layouts.admin_app')

@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Register') }}</div>

<div class="card-body">
<form method="POST" action="{{ route('admin.register') }}">
@csrf

<div class="form-group row">
<label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>

<div class="col-md-6">
<input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>

@error('name')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

<div class="col-md-6">
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">

@error('email')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

<div class="col-md-6">
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">

@error('password')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>

<div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>

<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
</div>
</div>

<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Register') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection



admin_home.blade.php

@extends('layouts.admin_app')

@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Dashboard</div>

<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif

Admin logged in!
</div>
</div>
</div>
</div>
</div>
@endsection


とりあえず完成


Auth::user()は何をとるのか

app.blade.phpとadmin_app.blade.phpにAuth::user()->nameという記述があります。

Screenshot_3.png

Screenshot_4.png

写真を見ると、それぞれのnameがちゃんと取れています。

これは、middlewareの引数でadminを渡しているおかげです。AdminHomeControllerのconstructの記述を引数adminなしにしてみます。

Screenshot_5.png

ルートは/admin/homeなのに、Auth::user()->nameは、useruserになっています。


もし、middleware(auth)を通さず、Auth::user()的なことを取得したい時(引数で分けたい)(管理者・一般ユーザー)

今回試すために、AdminHomeControllerのindexを利用します。ここで、userの情報を取ってみます。

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Auth;

class AdminHomeController extends Controller
{
public function __construct()
{

}

public function index()
{
dd(Auth::guard('user')->user());
}
}

Screenshot_6.png

とれています。guardに引数を指定すれば、ログイン中のユーザー情報がとれます。adminと指定すれば、adminのログイン中のユーザーの情報をとれます。