flarum / framework

Simple forum software for building great communities.
http://flarum.org/
6.39k stars 834 forks source link

Session object not available in controllers called through Api\Client during preload #2800

Closed clarkwinkelmann closed 3 years ago

clarkwinkelmann commented 3 years ago

Bug Report

Current Behavior It is not possible to access the session request attribute inside a request proxied through Flarum\Api\Client during preloading.

Steps to Reproduce

Save data in the session, for example through a middleware:

class MyMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $session = $request->getAttribute('session');

        $session->put('testing', 'Hello World');

        return $handler->handle($request);
    }
}

Register that middleware on either forum or api middelware stack and run it to set the value in session.

Then attempt to retrieve that value from ShowForumController, for example using the ApiController::prepareDataForSerialization extender:


class LoadTestingRelationship
{
    public function __invoke(ShowForumController $controller, &$data, ServerRequestInterface $request)
    {
        $session = $request->getAttribute('session');

        // Doesn't work, $session is null
        $data['testing'] = $session->get('testing');
    }
}
    (new Extend\ApiController(ShowForumController::class))
        ->prepareDataForSerialization(LoadTestingRelationship::class),

The code will work when accessing /api directly. However when loading /, the code fails when ShowForumController is used internally to set the boot payload.

Expected Behavior The session attribute should be available on the request in all contexts.

Ideally other request attributes added by middlewares should also be preserved.

Environment

Possible Solution The "quick" solution would be to do the same we do for actor attribute and extract session from the original request, pass it to Api\Client, then inject it back to the internal request object.

https://github.com/flarum/core/blob/94d69fe15fbcc459c84fcad5a0d5b274d9d7fe48/src/Frontend/Frontend.php#L68-L75

https://github.com/flarum/core/blob/94d69fe15fbcc459c84fcad5a0d5b274d9d7fe48/src/Api/Client.php#L60

Ideally I would prefer a solution where attributes can be explicitly whitelisted, since this also impacts attributes added by extensions, or the locale attribute.

Generally, this is a broader issue in the sense that no middlewares run for those internal requests, so should we just copy-paste the request attributes from the forum middleware stack. Or maybe we should refactor that code to actually run the API middleware stack on internal requests so those middlewares have a chance to add their own attributes.

Up to Flarum beta 16, a workaround is accessing the $session object through $actor->getSession(), but that method will be removed in the next version by #2784

Additional Context My impacted code is not publicly released yet, but I'm attaching additional data to the session and need to return it in the preload data. That data is actually extracted from the session into request attributes by a middleware, but I cannot access those attributes from ApiController::prepareDataForSerialization

askvortsov1 commented 3 years ago

run the API middleware stack on internal requests so those middlewares have a chance to add their own attributes.

I have a PR open for this. https://github.com/flarum/core/pull/2783