Laravel5.6 ドメインルーティング+マルチ認証
いじってる間にLaravel5.7が出てしまったけど5.6です。多分変わってないはず。
前提条件
- Laravel5.6をcomposerでインストール済み
composer create-project --prefer-dist laravel/laravel myapp "5.6.*" - DocumentRootはpublicディレクトリを指定。その他AllowOverride All等も適宜設定済み
DocumentRoot "/var/www/html/myapp/public" - データベースを利用できるよう設定済み
やりたいこと
- 接続時のドメインでフロントエンドとバックエンドに振り分ける
- フロントエンドとバックエンドで異なるDBテーブルのユーザーで認証する
- ログインIDはメールアドレスではなく独自で発行したものを使用する
※ユーザー登録、パスワードリセットは取り扱わない
マイグレーション
php artisan make:migration create_members_table
public function up()
{
Schema::create('members', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('loginid')->unique();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
create_admins_tableも同様に作成する。
マイグレーションを実行する
php artisan migrate
Eloquentモデルを作成
Illuminate\Database\Eloquent\ModelではなくIlluminate\Foundation\Auth\Userを継承する。
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Member extends Authenticatable
{
/** @var array */
protected $fillable = [
'name', 'loginid', 'password',
];
/** @var array */
protected $hidden = [
'password', 'remember_token',
];
}
app/Admin.phpも同様に作成する。
ユーザーデータ作成
php artisan tinker 等で作成しておく。
>>> $member = App\Member::create(['name' => 'Tester', 'loginid' => 'tester', 'password' => Hash::make('password')]);
>>> $admin = App\Admin::create(['name' => 'Admin', 'loginid' => 'admin', 'password' => Hash::make('password')]);
認証設定
ガードとプロバイダーにフロントエンド用、バックエンド用を設定する。
<?php
return [
'defaults' => [
'guard' => 'front', // webは使用しないのでfrontに変更
'passwords' => 'users',
],
'guards' => [ // webを削除してfrontとbackを追加
'front' => [
'driver' => 'session',
'provider' => 'members',
],
'back' => [
'driver' => 'session',
'provider' => 'admins',
],
],
'providers' => [ // 作成したEloquentモデルを指定
'members' => [
'driver' => 'eloquent',
'model' => App\Member::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
],
ルーティング
ドメインでルーティングを分ける。フロントエンドとバックエンドのドメインを変えることでセッションCookieの競合も解決出来るので一石二鳥。
ここではlocalhost => App\Http\Controllers\Front, 127.0.0.1 => App\Http\Controllers\Back以下のコントローラーを利用するようにする。
Route::group(['domain' => 'localhost', 'namespace' => 'Front'], function () {
Route::get('/login', 'Auth\LoginController@showLoginForm');
Route::post('/login', 'Auth\LoginController@login');
Route::post('/logout', 'Auth\LoginController@logout');
Route::middleware(['auth:front'])->group(function () {
// 認証が必要な画面はこの下に記述
Route::get('/home', 'HomeController@index');
});
});
Route::group(['domain' => '127.0.0.1', 'namespace' => 'Back'], function () {
Route::get('/login', 'Auth\LoginController@showLoginForm');
Route::post('/login', 'Auth\LoginController@login');
Route::post('/logout', 'Auth\LoginController@logout');
Route::middleware(['auth:back'])->group(function () {
// 認証が必要な画面はこの下に記述
Route::get('/home', 'HomeController@index');
});
});
未認証時のリダイレクト先を設定
デフォルトはroute('login')にリダイレクトするようになっているので調整する。
Handler->unauthenticatedを追加する。
バックエンドはログイン画面に、フロントエンドはトップにリダイレクトする。
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['message' => $exception->getMessage()], 401);
}
if (in_array('back', $exception->guards())) {
return redirect()->guest(url('/login'));
}
if (in_array('front', $exception->guards())) {
return redirect()->guest(url('/'));
}
return redirect()->guest(url('/'));
}
コントローラーの作成
ログイン画面
<?php
namespace App\Http\Controllers\Front\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
use AuthenticatesUsers;
/**
* ログイン後に遷移する画面を設定する
*
* @var string
*/
protected $redirectTo = '/home';
public function __construct()
{
$this->middleware('guest')->except('logout');
}
/**
* ログインIDに使用する項目を設定する
*
* @return string
*/
public function username()
{
return 'loginid';
}
/**
* 認証に使用するguardを設定する
*
* @return mixed
*/
public function guard()
{
return Auth::guard('front');
}
}
ログイン後に表示する画面
<?php
namespace App\Http\Controllers\Front;
use App\Http\Controllers\Controller;
class HomeController extends Controller
{
public function index()
{
return view('home');
}
}
Backも同様に作成する。
ビューの作成
php artisan make:authを実行した際に作成されるものを参考に適宜作成。
route('login')等の名前付きルートURLは使用せず、url('/login')等に置き換える。
※テンプレートを共用するための措置。分けるのであればルート側で適宜名前を付けてもよい。
内容は割愛
@extends('layouts.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="{{ url('/login') }}" aria-label="{{ __('Login') }}">
@csrf
<div class="form-group row">
<label for="email" class="col-sm-4 col-form-label text-md-right">{{ __('Login ID') }}</label>
<div class="col-md-6">
<input id="loginid" type="text" class="form-control{{ $errors->has('loginid') ? ' is-invalid' : '' }}" name="loginid" value="{{ old('loginid') }}" required autofocus>
@if ($errors->has('loginid'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('loginid') }}</strong>
</span>
@endif
</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{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" required>
@if ($errors->has('password'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</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
@extends('layouts.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
You are logged in!
@auth('front')
Front
@endauth
@auth('back')
Back
@endauth
</div>
</div>
</div>
</div>
</div>
@endsection
確認
http://localhost/login にフロントエンド用のユーザーで、
http://127.0.0.1/login にバックエンド用のユーザーでログインでき、
逆にしてエラーになればOK。