ユーザー認証
前回終了時のソースコード
Laravelを使ったアプリケーション開発のソースコードは以下のようにしてダウンロードすることができます。
$ git clone https://kiku3.tsbio.info/git/study-laravel.git study_laravel
この章開始時点のソースコードは chapt6 ブランチにあります。
$ git switch chapt6
ソースコードを自分で書いていく場合は、自分用のブランチをつくるとよいです。
$ git switch -c my6 chapt6
Laravelのコードはsrcディレクトリからの相対パスになっています。
認証に必要なパッケージをインストールする
ユーザー認証に使うLaravel Breezeをインストールします。これは特に追加パッケージをインストールするものではなく、ルートなどを設定します。 これをインストールすると、次のファイルが上書きされてしまうので、コピーをつくっておきます。(web.phpはないとエラーがでる)
- app.css -> lab.css
- app.js -> lab.css
- app.blade.php -> lab.blade.php
- web.php -> oligo.php
# composer require laravel/breeze --dev # artisan breeze:install blade
breezeに変更されたファイルの修正
resources/views/layouts/app.blade.php を breeze.blade.phpに変更します。ついで、app/View/Components/AppLayout.php
の return view('layouts.app'); を return view('layouts.blade'); に修正します。lab.blade.phpをapp.blade.phpに戻します。
app/View/Components/AppLayout.php
<?php
namespace App\View\Components;
use Illuminate\View\Component;
use Illuminate\View\View;
class AppLayout extends Component
{
/**
* Get the view / contents that represents the component.
*/
public function render(): View
{
return view('layouts.breeze'); // layouts/app.blade.phpは自分用に
}
}
resources/css/app.css
@import 'tailwindcss';
@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';
@source '../../storage/framework/views/*.php';
@theme {
--font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
'Segoe UI Symbol', 'Noto Color Emoji';
}
@import 'lab.css';
@import 'oligo.css';
resources/css/lab.css
.module-tab {
@apply
border border-black /* 枠線の設定 */
first:rounded-l /* first: によって、最初の要素に限定する。左側(-l)のみ丸める(rounded)。 */
last:rounded-r /* 同様に最後の枠線の右側(-r)を丸める。 */
font-sans font-bold
px-6 bg-white /* 文字の左右の余白(padding x)を6px、背景色を白に設定 */
hover:bg-blue-500 hover:text-white /* ホバー時の背景色を青、文字色を白に設定 */
;
}
.feature-tabs {
@apply flex;
}
.feature-tab {
@apply border-t border-x border-black rounded-t-md mx-1 px-6 font-sans font-bold;
}
.features {
@apply bg-white p-2 min-h-screen;
}
button {
@apply border-2 py-[0.05em] px-2 rounded shadow-sm shadow-gray-400;
}
button:active {
@apply shadow-none translate-y-[0.05em] translate-x-[0.05em];
}
input[type=checkbox] {
@apply w-4 h-4;
}
lab.jsはそのままapp.jsに戻す
ユーザーの登録
/registerを使ったユーザーの登録はLaravelからメールを送信できるようにしないといけないので、今回はパス。
代わりに、Model/Userから直接登録する。
# ./artisan tinker > $user = User::create(['name' => 'test user', 'email' => 'test@example.com', 'password' => 'secret']) > exit
これで/loginでログインできるようになる。
ログインのしくみ
routes/web.phpを見てみると次のようになっている。
routes/web.php
<?php
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});
require __DIR__.'/auth.php';
routes/auth.php
<?php
use App\Http\Controllers\Auth\AuthenticatedSessionController;
use App\Http\Controllers\Auth\ConfirmablePasswordController;
use App\Http\Controllers\Auth\EmailVerificationNotificationController;
use App\Http\Controllers\Auth\EmailVerificationPromptController;
use App\Http\Controllers\Auth\NewPasswordController;
use App\Http\Controllers\Auth\PasswordController;
use App\Http\Controllers\Auth\PasswordResetLinkController;
use App\Http\Controllers\Auth\RegisteredUserController;
use App\Http\Controllers\Auth\VerifyEmailController;
use Illuminate\Support\Facades\Route;
Route::middleware('guest')->group(function () {
Route::get('register', [RegisteredUserController::class, 'create'])
->name('register');
Route::post('register', [RegisteredUserController::class, 'store']);
Route::get('login', [AuthenticatedSessionController::class, 'create'])
->name('login');
Route::post('login', [AuthenticatedSessionController::class, 'store']);
Route::get('forgot-password', [PasswordResetLinkController::class, 'create'])
->name('password.request');
Route::post('forgot-password', [PasswordResetLinkController::class, 'store'])
->name('password.email');
Route::get('reset-password/{token}', [NewPasswordController::class, 'create'])
->name('password.reset');
Route::post('reset-password', [NewPasswordController::class, 'store'])
->name('password.store');
});
Route::middleware('auth')->group(function () {
Route::get('verify-email', EmailVerificationPromptController::class)
->name('verification.notice');
Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
->middleware(['signed', 'throttle:6,1'])
->name('verification.verify');
Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
->middleware('throttle:6,1')
->name('verification.send');
Route::get('confirm-password', [ConfirmablePasswordController::class, 'show'])
->name('password.confirm');
Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']);
Route::put('password', [PasswordController::class, 'update'])->name('password.update');
Route::post('logout', [AuthenticatedSessionController::class, 'destroy'])
->name('logout');
});
/login は routes/auth.php に定義されている。ここで
Route::middleware('guest')->group(function () {
Route::get('login', [AuthenticatedSessionController::class, 'create'])
->name('login');
});
loginの情報は app/Http/Controllers/Auth/AuthenticatedSessionController.php に送られる。この中の store メソッド中で、 LoginRequest $response->authenticate() が認証を行っている。
さらに中身をみていくと
src/app/Http/Requests/Auth/LoginRequest.php で、Auth::attempt($this->only('email’, 'password’) という処理があり、ここで認証が行われる。
ヒント: ログインにemailではなくnameを使いたいときは、LoginRequestのrulesでnameを設定し、attemptでそれを渡すようにする。ユーザーにIDを設定したいときは、migration/create_users_table.phpを書き換えて、usersにuidなどのカラムを追加し、それをLoginRequestで受け取るようにする。
認証済みユーザーに限定する
/oligoへのアクセスに認証を必要とするように変更する。
routes/oligo.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\OligoController;
// オリゴDNAのデータベース
Route::middleware(['auth', 'verified']) //
/* authとverifiedというミドルウェアを通過することを要求
* これらのミドルウェアは vendor/laravel/framework/src/Illuminate/Auth/Middleware/ に存在する。
* auth -> Authenticate.php
* verified -> EnsureEmailIsVerified.php
*/
->prefix('/oligo')
->as('web.oligo.')
->group(function (){
Route::get('/', [OligoController::class, 'index'])->name('index');
Route::get('/search', [OligoController::class, 'search'])->name('search');
Route::get('/create', [OligoController::class, 'create'])->name('create');
Route::post('/', [OligoController::class, 'store'])->name('store');
// 編集フォームとデータ更新
Route::get('/edit', [OligoController::class, 'edit'])->name('edit');
Route::put('/{item}', [OligoController::class, 'update'])->name('update');
});
これをweb.phpで読み込むようにする
routes/web.php
<?php
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});
require __DIR__.'/auth.php';
require __DIR__.'/oligo.php';
誰が承認されているのかわかるようにヘッダー部分にいれる。ついでにログアウトできるようにする。
resources/views/layouts/app.blade.php
@extends('layouts.html')
@section('body')
<header class='bg-blue-500 text-white py-2 px-2 flex justify-between items-start'> {{-- 背景色、文字色、余白(padding) --}}
<h1 class='text-xl leading-none'>{{ config('app.name') }}</h1>
<div class="flex items-baseline">
@auth
<span class='px-2 text-sm'>{{ auth()->user()->name }}</span>
<form method="POST" action="{{ route('logout') }}" class="inline">
@csrf
<button type="submit" class="text-sm text-black bg-gray-200 border-gray-400 px-2 hover:bg-gray-400 hover:text-white">
{{ __('ログアウト') }}
</button>
</form>
@endauth
@guest
ゲスト
@endguest
</div>
</header>
<nav class='bg-yellow-100 py-2 px-2'>
<ul id='module-tabs' class='flex'> {{-- タブが横並びになるようにflexを追加 --}}
<li class='module-tab'><a id='oligo-tab' href='/oligo'>オリゴDNA</a></li>
{{-- モジュールが複数並んだときの様子がわかるようにダミーを追加 --}}
<li class='module-tab'><a id='dummy1-tab' href='/dummy1'>ダミー1</a></li>
<li class='module-tab'><a id='dummy2-tab' href='/dummy2'>ダミー2</a></li>
<li class='module-tab'><a id='dummy3-tab' href='/dummy3'>ダミー3</a></li>
</ul>
</nav>
<main id='modules' class='bg-yellow-100 px-2 min-h-screen'>
@yield('module')
button {
@apply border-2 py-[0.05em] px-2 rounded shadow-sm shadow-gray-400;
}
button:active {
@apply shadow-none translate-y-[0.05em] translate-x-[0.05em];
}
input[type=checkbox] {
@apply w-4 h-4;
}
</main>
@endsection
/loginを直接URLに指定したとき、ログイン後に/dashboardへリダイレクトされます。これはapp/Http/Controllers/Auth/AuthenticatedSessionController.phpに設定があり、リダイレクト先を変更できます。
ユーザーの一覧、追加、編集、削除
oligoモジュールをコピーして少しずつ合わせる
必要なもの
- routes/users.php -> web.phpから読み込む
- UserController.php UserRequest.php UserService.php
- views/user
- css/user.css <- モジュールごとに色を変えるとか