BreezeはLaravelで使える認証パッケージ
Breezeは、認証機能を備えたLaravelアプリケーションを構築するための最小限かつシンプルな出発点を提供します。
インストール
$ composer require laravel/breeze --dev
$ php artisan breeze:install
$ yarn
$ yarn dev
route:list
インストール時にroutes/auth.phpが作成され、routes/web.phpでrequireされて読み込まれます。
認証関係のrouteが追加されます。
+--------+----------+---------------------------------+---------------------+-------------------------------------------------------------------------+--------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+----------+---------------------------------+---------------------+-------------------------------------------------------------------------+--------------+
| | GET|HEAD | / | | Closure | web |
| | GET|HEAD | api/user | | Closure | api |
| | | | | | auth:api |
| | POST | confirm-password | | App\Http\Controllers\Auth\ConfirmablePasswordController@store | web |
| | | | | | auth |
| | GET|HEAD | confirm-password | password.confirm | App\Http\Controllers\Auth\ConfirmablePasswordController@show | web |
| | | | | | auth |
| | GET|HEAD | dashboard | dashboard | Closure | web |
| | | | | | auth |
| | POST | email/verification-notification | verification.send | App\Http\Controllers\Auth\EmailVerificationNotificationController@store | web |
| | | | | | auth |
| | | | | | throttle:6,1 |
| | POST | forgot-password | password.email | App\Http\Controllers\Auth\PasswordResetLinkController@store | web |
| | | | | | guest |
| | GET|HEAD | forgot-password | password.request | App\Http\Controllers\Auth\PasswordResetLinkController@create | web |
| | | | | | guest |
| | POST | login | | App\Http\Controllers\Auth\AuthenticatedSessionController@store | web |
| | | | | | guest |
| | GET|HEAD | login | login | App\Http\Controllers\Auth\AuthenticatedSessionController@create | web |
| | | | | | guest |
| | POST | logout | logout | App\Http\Controllers\Auth\AuthenticatedSessionController@destroy | web |
| | | | | | auth |
| | POST | register | | App\Http\Controllers\Auth\RegisteredUserController@store | web |
| | | | | | guest |
| | GET|HEAD | register | register | App\Http\Controllers\Auth\RegisteredUserController@create | web |
| | | | | | guest |
| | POST | reset-password | password.update | App\Http\Controllers\Auth\NewPasswordController@store | web |
| | | | | | guest |
| | GET|HEAD | reset-password/{token} | password.reset | App\Http\Controllers\Auth\NewPasswordController@create | web |
| | | | | | guest |
| | GET|HEAD | verify-email | verification.notice | App\Http\Controllers\Auth\EmailVerificationPromptController@__invoke | web |
| | | | | | auth |
| | GET|HEAD | verify-email/{id}/{hash} | verification.verify | App\Http\Controllers\Auth\VerifyEmailController@__invoke | web |
| | | | | | auth |
| | | | | | signed |
| | | | | | throttle:6,1 |
+--------+----------+---------------------------------+---------------------+-------------------------------------------------------------------------+--------------+
register
登録ページは↓のrouteが使われる。
GET|HEAD App\Http\Controllers\Auth\RegisteredUserController@create
登録リクエストには↓が使われる
POST App\Http\Controllers\Auth\RegisteredUserController@store
store処理ではvalidate, login, homeへのリダイレクトが行われる。
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|confirmed|min:8',
]);
Auth::login($user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]));
event(new Registered($user));
return redirect(RouteServiceProvider::HOME);
}
Auth::login
Auth
ファサードでAuthManagerが返される。login関数が定義されていないので__callマジックメソッドが実行され、guardのlogin関数が実行される。
public function __call($method, $parameters)
{
return $this->guard()->{$method}(...$parameters);
}
$this->guard()ではドライバーが返される。$nameが指定されていないのでデフォルトドライバーが返される。
Authのデフォルトドライバーはconfigのauth.defaults.guardで指定されている。構築直後ではguardにweb(SessionDriver)が指定されている。
SessionDriverの実クラスはSessionGuardになる。
public function guard($name = null)
{
$name = $name ?: $this->getDefaultDriver();
return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
}
public function getDefaultDriver()
{
return $this->app['config']['auth.defaults.guard'];
}
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
SessionGuard->login()
Auth::login
ではSessionGuardのlogin()が実行される。
AuthenticatableContractインターフェースを受け取り、セッション更新, remember処理が行われる。
public function login(AuthenticatableContract $user, $remember = false)
{
$this->updateSession($user->getAuthIdentifier());
// If the user should be permanently "remembered" by the application we will
// queue a permanent cookie that contains the encrypted copy of the user
// identifier. We will then decrypt this later to retrieve the users.
if ($remember) {
$this->ensureRememberTokenIsSet($user);
$this->queueRecallerCookie($user);
}
// If we have an event dispatcher instance set we will fire an event so that
// any listeners will hook into the authentication events and run actions
// based on the login and logout events fired from the guard instances.
$this->fireLoginEvent($user, $remember);
$this->setUser($user);
}
$this->updateSession
putでセッションストアのプロパティにユーザーidを追加する。
migrate(true)でセッションの削除とセッションidの再設定を行う。
protected function updateSession($id)
{
$this->session->put($this->getName(), $id);
$this->session->migrate(true);
}
$this->ensureRememberTokenIsSet
RememberTokenがない場合にリメンバートークンを設定する
protected function ensureRememberTokenIsSet(AuthenticatableContract $user)
{
if (empty($user->getRememberToken())) {
$this->cycleRememberToken($user);
}
}
protected function cycleRememberToken(AuthenticatableContract $user)
{
$user->setRememberToken($token = Str::random(60));
$this->provider->updateRememberToken($user, $token);
}
login
↓でログイン処理が行われる。
POST App\Http\Controllers\Auth\AuthenticatedSessionController@store
public function store(LoginRequest $request)
{
$request->authenticate();
$request->session()->regenerate();
return redirect(RouteServiceProvider::HOME);
}
ログイン処理はLoginRequestのauthenticateで行われる。
RateLimitチェックとattempt実行を行う。
public function authenticate()
{
$this->ensureIsNotRateLimited();
if (! Auth::attempt($this->only('email', 'password'), $this->filled('remember'))) {
RateLimiter::hit($this->throttleKey());
throw ValidationException::withMessages([
'email' => __('auth.failed'),
]);
}
RateLimiter::clear($this->throttleKey());
}
Auth::attempt
SessionGuardのattemptが実行される。
プロバイダーからuserを取得して、hasValidCredentialsで資格情報のチェックし、問題なければloginする
public function attempt(array $credentials = [], $remember = false)
{
$this->fireAttemptEvent($credentials, $remember);
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
// If an implementation of UserInterface was returned, we'll ask the provider
// to validate the user against the given credentials, and if they are in
// fact valid we'll log the users into the application and return true.
if ($this->hasValidCredentials($user, $credentials)) {
$this->login($user, $remember);
return true;
}
// If the authentication attempt fails we will fire an event so that the user
// may be notified of any suspicious attempts to access their account from
// an unrecognized user. A developer may listen to this event as needed.
$this->fireFailedEvent($user, $credentials);
return false;
}
providerのvalidateCredentials関数で資格情報のバリデーションを行う。
protected function hasValidCredentials($user, $credentials)
{
$validated = ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
if ($validated) {
$this->fireValidatedEvent($user);
}
return $validated;
}
DatabaseUserPoviderのvalidateCredentialsでpasswordのチェックを行う。
public function validateCredentials(UserContract $user, array $credentials)
{
return $this->hasher->check(
$credentials['password'], $user->getAuthPassword()
);
}
logout
↓でログアウト処理を行う
POST App\Http\Controllers\Auth\AuthenticatedSessionController@destroy
webガードのlogout関数を実行しセッションの後始末をする。
public function destroy(Request $request)
{
Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}