Laravel7が標準で用意しているAuthでログインした時で行われていることを確認する。
(何度も同じことを調べるので、調べた結果をメモしておく)
GET /login
ログイン画面が表示される。
id/passを入力してLoginボタンをクリックするとPOST /login
がコールされる
POST /login
エントリポイント
ログイン認証処理で、routeを確認すると、LoginController@login
がコールされる
$ php artisan route:list
POST /login
-> App\Http\Controllers\Auth\LoginController@login
App\Http\Controllers\Auth\LoginController
LoginControllerはAuthenticatesUsersをuseしている。このファイル自体にlogin()メソッドはないが、AuthenticatesUsers traitをuseしている。
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
use AuthenticatesUsers;
protected $redirectTo = RouteServiceProvider::HOME;
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}
Illuminate\Foundation\Auth\AuthenticatesUsers
login()メソッドははtraitで実装されている。
trait AuthenticatesUsers
{
public function login(Request $request)
{
$this->validateLogin($request);
if (method_exists($this, 'hasTooManyLoginAttempts') &&
$this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
最初に出てくるvalidateLogin()はrequestをチェックしているだけ
protected function validateLogin(Request $request)
{
$request->validate([
$this->username() => 'required|string',
'password' => 'required|string',
]);
}
attemptLogin()にログイン処理は記載されてる
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->filled('remember')
);
}
attempt()は、セッションに認証を持つ場合SessionGuard::attempt()がコールされる。
namespace Illuminate\Auth;
class SessionGuard implements StatefulGuard, SupportsBasicAuth
{
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;
}
cookieはlogin()の処理で保存している
class SessionGuard implements StatefulGuard, SupportsBasicAuth
...
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);
}
updateSession()でセッションを登録する。
protected function updateSession($id)
{
$this->session->put($this->getName(), $id);
$this->session->migrate(true);
}
認証できたら、LoginController::redirectToで指定されたURLにリダイレクトする。(デフォルトではGET /home
がコールされる)
GET /home
エントリポイント
route:listをみると、GET /homeはHomeController@indexにマッピングされている
$ php artisan route:list
GET /home
-> App\Http\Controllers\HomeController@index
HomeControllerはコンストラクタでauthのmiddlewareを実行する
class HomeController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
このauthが何のクラスかは、app/Http/Kernel.phpで指定されている
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class
Authenticate::handle()は以下の通り。handle()は、処理をauthenticate()に任せて終わり
namespace Illuminate\Auth\Middleware;
class Authenticate implements AuthenticatesRequests
{
public function handle($request, Closure $next, ...$guards)
{
$this->authenticate($request, $guards);
return $next($request);
}
該当リクエストへのガードを取得してガードに認証を移譲する。ガードが空なら認証エラー
protected function authenticate($request, array $guards)
{
if (empty($guards)) {
$guards = [null];
}
foreach ($guards as $guard) {
if ($this->auth->guard($guard)->check()) {
return $this->auth->shouldUse($guard);
}
}
$this->unauthenticated($request, $guards);
}
ガードはconfig/auth.phpで指定されている。
例えば、$guards = ['web']だった時、$this->auth->guard($guard)は、Illuminate\Auth\SessionGuardを返す。
この対応ルールは、config/auth.phpで定義されている
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
SessionGuardは、check()を持っておらず、代わりにGuardHelpersトレイトをuseしている。
class SessionGuard implements StatefulGuard, SupportsBasicAuth
{
use GuardHelpers, Macroable;
GuardHelpersは、$this->user()がnullを返さなければ認証OKとしている。
namespace Illuminate\Auth;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\UserProvider;
/**
* These methods are typically the same across all guards.
*/
trait GuardHelpers
{
public function check()
{
return ! is_null($this->user());
}