mirror of
https://github.com/flarum/framework.git
synced 2024-11-25 17:57:04 +08:00
Bind session handling to request lifecycle
With this change, session objects are no longer instantiated globally, but instead created within a middleware during the request lifecycle. In addition, session garbage collection is integrated with the already existing middleware for this purpose.
This commit is contained in:
parent
5672819549
commit
bb49e24ffe
|
@ -718,8 +718,6 @@ class Application extends Container implements ApplicationContract
|
||||||
'filesystem.cloud' => [\Illuminate\Contracts\Filesystem\Cloud::class],
|
'filesystem.cloud' => [\Illuminate\Contracts\Filesystem\Cloud::class],
|
||||||
'hash' => [\Illuminate\Contracts\Hashing\Hasher::class],
|
'hash' => [\Illuminate\Contracts\Hashing\Hasher::class],
|
||||||
'mailer' => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
|
'mailer' => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
|
||||||
'session' => [\Illuminate\Session\SessionManager::class],
|
|
||||||
'session.driver' => [\Illuminate\Contracts\Session\Session::class],
|
|
||||||
'validator' => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class],
|
'validator' => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class],
|
||||||
'view' => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
|
'view' => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
|
||||||
];
|
];
|
||||||
|
|
|
@ -240,12 +240,8 @@ class Site
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'session' => [
|
'session' => [
|
||||||
'driver' => 'file',
|
|
||||||
'lifetime' => 120,
|
'lifetime' => 120,
|
||||||
'expire_on_close' => false,
|
|
||||||
'encrypt' => false,
|
|
||||||
'files' => $app->storagePath().'/sessions',
|
'files' => $app->storagePath().'/sessions',
|
||||||
'lottery' => [2, 100],
|
|
||||||
'cookie' => 'session'
|
'cookie' => 'session'
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -15,12 +15,30 @@ use Flarum\Http\AccessToken;
|
||||||
use Flarum\User\AuthToken;
|
use Flarum\User\AuthToken;
|
||||||
use Flarum\User\EmailToken;
|
use Flarum\User\EmailToken;
|
||||||
use Flarum\User\PasswordToken;
|
use Flarum\User\PasswordToken;
|
||||||
|
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||||
use Interop\Http\ServerMiddleware\DelegateInterface;
|
use Interop\Http\ServerMiddleware\DelegateInterface;
|
||||||
use Interop\Http\ServerMiddleware\MiddlewareInterface;
|
use Interop\Http\ServerMiddleware\MiddlewareInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
|
use SessionHandlerInterface;
|
||||||
|
|
||||||
class CollectGarbage implements MiddlewareInterface
|
class CollectGarbage implements MiddlewareInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var SessionHandlerInterface
|
||||||
|
*/
|
||||||
|
protected $sessionHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $sessionConfig;
|
||||||
|
|
||||||
|
public function __construct(SessionHandlerInterface $handler, ConfigRepository $config)
|
||||||
|
{
|
||||||
|
$this->sessionHandler = $handler;
|
||||||
|
$this->sessionConfig = $config->get('session');
|
||||||
|
}
|
||||||
|
|
||||||
public function process(Request $request, DelegateInterface $delegate)
|
public function process(Request $request, DelegateInterface $delegate)
|
||||||
{
|
{
|
||||||
$this->collectGarbageSometimes();
|
$this->collectGarbageSometimes();
|
||||||
|
@ -43,10 +61,17 @@ class CollectGarbage implements MiddlewareInterface
|
||||||
EmailToken::where('created_at', '<=', $earliestToKeep)->delete();
|
EmailToken::where('created_at', '<=', $earliestToKeep)->delete();
|
||||||
PasswordToken::where('created_at', '<=', $earliestToKeep)->delete();
|
PasswordToken::where('created_at', '<=', $earliestToKeep)->delete();
|
||||||
AuthToken::where('created_at', '<=', $earliestToKeep)->delete();
|
AuthToken::where('created_at', '<=', $earliestToKeep)->delete();
|
||||||
|
|
||||||
|
$this->sessionHandler->gc($this->getSessionLifetimeInSeconds());
|
||||||
}
|
}
|
||||||
|
|
||||||
private function hit()
|
private function hit()
|
||||||
{
|
{
|
||||||
return mt_rand(1, 100) <= 2;
|
return mt_rand(1, 100) <= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getSessionLifetimeInSeconds()
|
||||||
|
{
|
||||||
|
return $this->sessionConfig['lifetime'] * 60;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,19 +13,21 @@ namespace Flarum\Http\Middleware;
|
||||||
|
|
||||||
use Dflydev\FigCookies\FigResponseCookies;
|
use Dflydev\FigCookies\FigResponseCookies;
|
||||||
use Flarum\Http\CookieFactory;
|
use Flarum\Http\CookieFactory;
|
||||||
|
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||||
use Illuminate\Contracts\Session\Session;
|
use Illuminate\Contracts\Session\Session;
|
||||||
use Illuminate\Session\SessionManager;
|
use Illuminate\Session\Store;
|
||||||
use Interop\Http\ServerMiddleware\DelegateInterface;
|
use Interop\Http\ServerMiddleware\DelegateInterface;
|
||||||
use Interop\Http\ServerMiddleware\MiddlewareInterface;
|
use Interop\Http\ServerMiddleware\MiddlewareInterface;
|
||||||
use Psr\Http\Message\ResponseInterface as Response;
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
|
use SessionHandlerInterface;
|
||||||
|
|
||||||
class StartSession implements MiddlewareInterface
|
class StartSession implements MiddlewareInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var SessionManager
|
* @var SessionHandlerInterface
|
||||||
*/
|
*/
|
||||||
protected $manager;
|
protected $handler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var CookieFactory
|
* @var CookieFactory
|
||||||
|
@ -33,25 +35,29 @@ class StartSession implements MiddlewareInterface
|
||||||
protected $cookie;
|
protected $cookie;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SessionManager $manager
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $config;
|
||||||
|
|
||||||
|
/**
|
||||||
* @param CookieFactory $cookie
|
* @param CookieFactory $cookie
|
||||||
*/
|
*/
|
||||||
public function __construct(SessionManager $manager, CookieFactory $cookie)
|
public function __construct(SessionHandlerInterface $handler, CookieFactory $cookie, ConfigRepository $config)
|
||||||
{
|
{
|
||||||
$this->manager = $manager;
|
$this->handler = $handler;
|
||||||
$this->cookie = $cookie;
|
$this->cookie = $cookie;
|
||||||
|
$this->config = $config->get('session');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function process(Request $request, DelegateInterface $delegate)
|
public function process(Request $request, DelegateInterface $delegate)
|
||||||
{
|
{
|
||||||
$request = $request->withAttribute('session',
|
$request = $request->withAttribute(
|
||||||
$session = $this->startSession($request)
|
'session',
|
||||||
|
$session = $this->makeSession($request)
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->collectGarbage($session);
|
$session->start();
|
||||||
|
|
||||||
$response = $delegate->process($request);
|
$response = $delegate->process($request);
|
||||||
|
|
||||||
$session->save();
|
$session->save();
|
||||||
|
|
||||||
$response = $this->withCsrfTokenHeader($response, $session);
|
$response = $this->withCsrfTokenHeader($response, $session);
|
||||||
|
@ -59,37 +65,20 @@ class StartSession implements MiddlewareInterface
|
||||||
return $this->withSessionCookie($response, $session);
|
return $this->withSessionCookie($response, $session);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function startSession(Request $request)
|
private function makeSession(Request $request)
|
||||||
{
|
{
|
||||||
$session = $this->manager->driver();
|
$cookieName = $this->cookie->getName($this->config['cookie']);
|
||||||
|
|
||||||
$id = array_get($request->getCookieParams(), $this->cookie->getName($session->getName()));
|
return new Store(
|
||||||
|
$cookieName,
|
||||||
$session->setId($id);
|
$this->handler,
|
||||||
$session->start();
|
array_get($request->getCookieParams(), $cookieName)
|
||||||
|
);
|
||||||
return $session;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function collectGarbage(Session $session)
|
|
||||||
{
|
|
||||||
$config = $this->manager->getSessionConfig();
|
|
||||||
|
|
||||||
if ($this->configHitsLottery($config)) {
|
|
||||||
$session->getHandler()->gc($this->getSessionLifetimeInSeconds());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function configHitsLottery(array $config)
|
|
||||||
{
|
|
||||||
return random_int(1, $config['lottery'][1]) <= $config['lottery'][0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function withCsrfTokenHeader(Response $response, Session $session)
|
private function withCsrfTokenHeader(Response $response, Session $session)
|
||||||
{
|
{
|
||||||
$response = $response->withHeader('X-CSRF-Token', $session->token());
|
return $response->withHeader('X-CSRF-Token', $session->token());
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function withSessionCookie(Response $response, Session $session)
|
private function withSessionCookie(Response $response, Session $session)
|
||||||
|
@ -102,6 +91,6 @@ class StartSession implements MiddlewareInterface
|
||||||
|
|
||||||
private function getSessionLifetimeInSeconds()
|
private function getSessionLifetimeInSeconds()
|
||||||
{
|
{
|
||||||
return ($this->manager->getSessionConfig()['lifetime'] ?? null) * 60;
|
return $this->config['lifetime'] * 60;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@ use Flarum\Event\ConfigureUserPreferences;
|
||||||
use Flarum\Event\GetPermission;
|
use Flarum\Event\GetPermission;
|
||||||
use Flarum\Foundation\AbstractServiceProvider;
|
use Flarum\Foundation\AbstractServiceProvider;
|
||||||
use Illuminate\Contracts\Container\Container;
|
use Illuminate\Contracts\Container\Container;
|
||||||
|
use Illuminate\Session\FileSessionHandler;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
use SessionHandlerInterface;
|
||||||
|
|
||||||
class UserServiceProvider extends AbstractServiceProvider
|
class UserServiceProvider extends AbstractServiceProvider
|
||||||
{
|
{
|
||||||
|
@ -23,6 +25,26 @@ class UserServiceProvider extends AbstractServiceProvider
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function register()
|
public function register()
|
||||||
|
{
|
||||||
|
$this->registerSession();
|
||||||
|
$this->registerGate();
|
||||||
|
$this->registerAvatarsFilesystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function registerSession()
|
||||||
|
{
|
||||||
|
$this->app->singleton('session.handler', function ($app) {
|
||||||
|
return new FileSessionHandler(
|
||||||
|
$app['files'],
|
||||||
|
$app['config']['session.files'],
|
||||||
|
$app['config']['session.lifetime']
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->app->alias('session.handler', SessionHandlerInterface::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function registerGate()
|
||||||
{
|
{
|
||||||
$this->app->singleton('flarum.gate', function ($app) {
|
$this->app->singleton('flarum.gate', function ($app) {
|
||||||
return new Gate($app, function () {
|
return new Gate($app, function () {
|
||||||
|
@ -32,8 +54,6 @@ class UserServiceProvider extends AbstractServiceProvider
|
||||||
|
|
||||||
$this->app->alias('flarum.gate', 'Illuminate\Contracts\Auth\Access\Gate');
|
$this->app->alias('flarum.gate', 'Illuminate\Contracts\Auth\Access\Gate');
|
||||||
$this->app->alias('flarum.gate', Gate::class);
|
$this->app->alias('flarum.gate', Gate::class);
|
||||||
|
|
||||||
$this->registerAvatarsFilesystem();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function registerAvatarsFilesystem()
|
protected function registerAvatarsFilesystem()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user