php - Symfony3 sub request lose of session -
i experience strange behavior when doing sub requests symfony 3.
the context
i think it's better explain why leads problem, may find solution. can skip part if it's read.
i've developped kind of clone of api platform, not fork, inspired rewrite. 1 of functionality wanted add ability call api server side.
the api lot of work (works relations example) it's useful let work of persisting / filtering, etc, classic server side app (no ajax calls).
the simplest way i've found sub requests. current implementation looks when used :
// collection of articles (output array) $this->proxy->get(article::class)->collection($page, $itemsperpages, $filters, $ordering)->asarray(); // single article (output entities) $this->proxy->get(article::class)->item('a2ck2')->asobject(); // persist article (output entities) $this->proxy->persist(article::class)->item(['title' => 'super article'])->asobject();
you idea.
when call as*
method, request executed, , code simple :
// proxy.php public function execute(request $request, response &$response = null) { $response = $this->kernel->handle($request); [...] // handle response status code, content etc. not important here. }
the request given in parameter of execute
method built (here builder shown):
// getrequestbuilder.php protected function createrequest(): request { $currentrequest = $this->getcurrentrequest(); $request = request::create( $this->generateuri([...]), request::method_get, [], $currentrequest->cookies->all() ); return $request; }
the problem
a problem occurs when have multiple firewalls , when sub request matches route in different firewall 1 of original request.
for following security
configuration :
# app/config/security.yml security: encoders: appbundle\entity\user: algorithm: bcrypt providers: main: id: app.main_user_provider doctrine: entity: class: appbundle:user property: username firewalls: backend: pattern: ^/admin anonymous: ~ logout: path: /admin/logout target: /admin/login invalidate_session: true stateless: false guard: entry_point: app.backend.login_form_authenticator authenticators: [app.backend.login_form_authenticator] frontend: pattern: ^/ anonymous: ~ logout: path: /logout target: /login invalidate_session: true stateless: false guard: entry_point: app.frontend.login_form_authenticator authenticators: [app.frontend.login_form_authenticator]
if sub request admin route route matching frontend
firewall, lose admin session.
if dump session before , after api call, gives me following :
array (size=3) '_security.backend.target_path' => string 'http://localhost/admin/api/formation/categories' (length=51) '_csrf/form' => string 'wt9js9b8det00xanugeq23qxfqy8uhrt_j5i6d9btj8' (length=43) '_security_backend' => string 'c:67:"symfony\component\security\guard\token\postauthenticationguardtoken":1786:{a:2:{i:0;s:7:"backend";i:1;s:174'... (length=1868)
and after sub request :
array (size=2) '_security.backend.target_path' => string 'http://localhost/admin/api/formation/categories' (length=51) '_csrf/form' => string 'wt9js9b8det00xanugeq23qxfqy8uhrt_j5i6d9btj8' (length=43)
the _security_backend
key gone, , session.
if don't copy cookies of original request sub request, session not lost, have problem if api route secured:
// getrequestbuilder.php protected function createrequest(): request { $currentrequest = $this->getcurrentrequest(); $request = request::create( $this->generateuri([...]), request::method_get, [], // removing line , replace empty array solves problem of loosing session. // if target route behind "backend" firewall, sub request redirected login page. $currentrequest->cookies->all() ); return $request; }
my questions
1) see think method of doing sub requests robust enough or know better way achieve same result?
on side note: don't curl or other way real http requests because want ability entities (actual objects) result of api call.
2) know way prevent original session lost if sub request matches route different firewall? understand right now, way see detect (no idea how..) if target route on same firewall or not, , copy cookies if so.. seems hard , hard have stable. , looks dirty **.
any idea appreciated.
thanks help.
i post own answer because found ugly way seems work handle case, feel really dirty , greatful if can think of clean way handle case.
so solution "backup" session data before request , restore after... did this:
// proxy.php public function execute(request $request, response &$response = null) { try { $this->savesession(); $response = $this->kernel->handle($request); [...] // handle response status code, content etc. not important here. } { $this->restoresession(); } } /** * saves current session. */ private function savesession() { $this->sessionstack[] = (array)$this->session->all(); } /** * restores latest session saved using savesession(). */ private function restoresession() { $data = array_pop($this->sessionstack); $this->session->clear(); foreach ($data $k => $v) { $this->session->set($k, $v); } }
and, of course, still copy cookies of current request in sub-request.
it's basic seems work (for current case @ least). have no idea of side effects of copying session data this, can guess it's bad thing.
it works because need keep _security_backend
key serialized object, "backupable" string. if in future cases session holds real objects being modified in sub-request, not work @ all.
and performance if session holds lot of data? hmm
so if of have better solution, i'm ears :)
Comments
Post a Comment