Laravel sessionの仕組みを追う
SessionServiceProvider.phpでSessionの仕組みがLaravelで使えるようになる。
ここでは、
- SessionManagerの登録
- SessionDriverの登録
- StartSession::classのDI登録
を行う。
public function register()
{
$this->registerSessionManager();
$this->registerSessionDriver();
$this->app->singleton(StartSession::class, function () {
return new StartSession($this->app->make(SessionManager::class), function () {
return $this->app->make(CacheFactory::class);
});
});
}
registerSessionManager
sessionをキーにSessionManagerを登録する。
protected function registerSessionManager()
{
$this->app->singleton('session', function ($app) {
return new SessionManager($app);
});
}
registerSessionDriver
session.storeでセッションのドライバーが返るようにする。
protected function registerSessionDriver()
{
$this->app->singleton('session.store', function ($app) {
// First, we will create the session manager which is responsible for the
// creation of the various session drivers when they are needed by the
// application instance, and will resolve them on a lazy load basis.
return $app->make('session')->driver();
});
}
StartSession
StartSessionはミドルウェアでKernel.phpの$middlewareGroupsで指定されている。
StartSessionでセッション処理の起動を行う
protected $middlewareGroups = [
'web' => [
\Illuminate\Session\Middleware\StartSession::class,
略...
],
handle関数では以下を行っている。
- session設定されているか確認し、設定されていないなら次のミドルウェアに処理を進める
- sessionドライバーを取得
- ブロックの有無に合わせてセッション管理
public function handle($request, Closure $next)
{
if (! $this->sessionConfigured()) {
return $next($request);
}
$session = $this->getSession($request);
if ($this->manager->shouldBlock() ||
($request->route() instanceof Route && $request->route()->locksFor())) {
return $this->handleRequestWhileBlocking($request, $session, $next);
} else {
return $this->handleStatefulRequest($request, $session, $next);
}
}
getSession
getSessionではsessionIdをセットしたドライバーを返す。
$this->manager->driver()
ではSessionManagerインスタンスのdriver関数を実行する。
driver関数ではconfigのsession.phpのdriverで指定したdriverインスタンスを返す。
public function getSession(Request $request)
{
// $session->getName()はconfigのsession.cookieの値。それを元にcookie値を取得する。
return tap($this->manager->driver(), function ($session) use ($request) {
$session->setId($request->cookies->get($session->getName()));
});
}
driverとしてどのインスタンスが返されるかはSessionManagerをみると分かる。
ドライバー作成時にcreateOOOODriver()関数が実行される。OOOはドライバー名。
SessionManagerには↓のような関数があり、具体的なインスタンスが分かる。
protected function createFileDriver()
{
return $this->createNativeDriver();
}
createNativeDriverではbuildSession関数で暗号するしないの設定に合わせてstoreインスタンスを返します。
ドライバーごとにhandlerインスタンスを作成し、storeインスタンスに渡す。
protected function createNativeDriver()
{
$lifetime = $this->config->get('session.lifetime');
return $this->buildSession(new FileSessionHandler(
$this->container->make('files'), $this->config->get('session.files'), $lifetime
));
}
handleStatefulRequest
handleStatefulRequest関数では以下を行う
- セッションを開始
- 一定の確率でゴミ掃除
- 次のmiddlewareを実行
- 必要ならsessionに現在のurlを設定
- cookieにsessionを登録
protected function handleStatefulRequest(Request $request, $session, Closure $next)
{
// If a session driver has been configured, we will need to start the session here
// so that the data is ready for an application. Note that the Laravel sessions
// do not make use of PHP "native" sessions in any way since they are crappy.
$request->setLaravelSession(
$this->startSession($request, $session)
);
$this->collectGarbage($session);
$response = $next($request);
$this->storeCurrentUrl($request, $session);
$this->addCookieToResponse($response, $session);
// Again, if the session has been configured we will need to close out the session
// so that the attributes may be persisted to some storage medium. We will also
// add the session identifier cookie to the application response headers now.
$this->saveSession($request);
return $response;
}
startSession
setRequestOnHandlerで必要な場合はハンドラーにリクエストをセットする。(現状CookieSessionHandlerのみ)
start関数では以下を行う
- sessionをload
- _tokenがあればtokenを再作成
protected function startSession(Request $request, $session)
{
return tap($session, function ($session) use ($request) {
$session->setRequestOnHandler($request);
$session->start();
});
}
public function start()
{
$this->loadSession();
if (! $this->has('_token')) {
$this->regenerateToken();
}
return $this->started = true;
}
addCookieToResponse
cookieにsessionIdを登録する
protected function addCookieToResponse(Response $response, Session $session)
{
if ($this->sessionIsPersistent($config = $this->manager->getSessionConfig())) {
$response->headers->setCookie(new Cookie(
$session->getName(), $session->getId(), $this->getCookieExpirationDate(),
$config['path'], $config['domain'], $config['secure'] ?? false,
$config['http_only'] ?? true, false, $config['same_site'] ?? null
));
}
}