Optimize anonymous public sessions

This commit is contained in:
2026-05-01 11:42:10 +02:00
parent 35011001ba
commit 961d21e91e
35 changed files with 888 additions and 66 deletions

View File

@@ -0,0 +1,122 @@
<?php
declare(strict_types=1);
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Session\Middleware\StartSession;
use Symfony\Component\HttpFoundation\Response;
class ConditionalStartSession extends StartSession
{
public function handle($request, Closure $next): mixed
{
if (! $request instanceof Request || ! config('skinbase-sessions.enabled', true)) {
return parent::handle($request, $next);
}
if ($this->shouldSkipSession($request)) {
$request->attributes->set('skinbase.session_skipped', true);
$response = $next($request);
if ($response instanceof Response && config('skinbase-sessions.debug_header', false)) {
$response->headers->set('X-Skinbase-Session', 'skipped');
}
return $response;
}
$request->attributes->set('skinbase.session_skipped', false);
$response = parent::handle($request, $next);
if ($response instanceof Response && config('skinbase-sessions.debug_header', false)) {
$response->headers->set('X-Skinbase-Session', 'started');
}
return $response;
}
protected function shouldSkipSession(Request $request): bool
{
if (! $this->isSafeReadMethod($request)) {
return false;
}
if ($this->hasExistingSessionCookie($request)) {
return false;
}
if ($this->matchesAnyPath($request, config('skinbase-sessions.always_session_paths', []))) {
return false;
}
if (! $this->matchesAnyPath($request, config('skinbase-sessions.public_paths', []))) {
return false;
}
if (config('skinbase-sessions.skip_anonymous_public_get', true)) {
return true;
}
return config('skinbase-sessions.skip_known_crawlers_on_public_get', true)
&& $this->isKnownCrawler($request);
}
protected function isSafeReadMethod(Request $request): bool
{
return in_array($request->getMethod(), ['GET', 'HEAD'], true);
}
protected function hasExistingSessionCookie(Request $request): bool
{
$cookieName = config('session.cookie');
return is_string($cookieName)
&& $cookieName !== ''
&& $request->cookies->has($cookieName);
}
protected function matchesAnyPath(Request $request, array $patterns): bool
{
foreach ($patterns as $pattern) {
if (! is_string($pattern) || $pattern === '') {
continue;
}
if ($pattern === '/' && $request->path() === '/') {
return true;
}
$normalizedPattern = trim($pattern, '/');
if ($normalizedPattern !== '' && $request->is($normalizedPattern)) {
return true;
}
}
return false;
}
protected function isKnownCrawler(Request $request): bool
{
$userAgent = strtolower((string) $request->userAgent());
if ($userAgent === '') {
return false;
}
foreach (config('skinbase-sessions.bot_user_agent_keywords', []) as $keyword) {
$normalizedKeyword = strtolower((string) $keyword);
if ($normalizedKeyword !== '' && str_contains($userAgent, $normalizedKeyword)) {
return true;
}
}
return false;
}
}