From 2f4d90614dfa70536e2fc565d5b76bef4ecf3e80 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rapha=C3=ABl=20Gertz?= Date: Wed, 11 Dec 2019 05:39:50 +0100 Subject: [PATCH] Add logout success handler that redirect on referer when possible --- Security/LogoutSuccessHandler.php | 110 ++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 Security/LogoutSuccessHandler.php diff --git a/Security/LogoutSuccessHandler.php b/Security/LogoutSuccessHandler.php new file mode 100644 index 0000000..de4d960 --- /dev/null +++ b/Security/LogoutSuccessHandler.php @@ -0,0 +1,110 @@ +router = $router; + } + + /** + * {@inheritdoc} + */ + public function onLogoutSuccess(Request $request) { + //Retrieve logout route + $logout = $request->get('_route'); + + //Extract and process referer + if ($referer = $request->headers->get('referer')) { + //Create referer request instance + $req = Request::create($referer); + + //Get referer path + $path = $req->getPathInfo(); + + //Get referer query string + $query = $req->getQueryString(); + + //Remove script name + $path = str_replace($request->getScriptName(), '', $path); + + //Try with referer path + try { + //Retrieve route matching path + $route = $this->router->match($path); + + //Verify that it differ from current one + if (($name = $route['_route']) == $logout) { + throw new ResourceNotFoundException('Identical referer and logout route'); + } + + //Remove route and controller from route defaults + unset($route['_route'], $route['_controller']); + + //Generate url + $url = $this->router->generate($name, $route); + //No route matched + } catch(ResourceNotFoundException $e) { + //Unset referer to fallback to default route + unset($referer); + } + } + + //Referer empty or unusable + if (empty($referer)) { + //Try with / path + try { + //Retrieve route matching / + $route = $this->router->match('/'); + + //Verify that it differ from current one + if (($name = $route['_route']) == $logout) { + throw new ResourceNotFoundException('Identical referer and logout route'); + } + + //Remove route and controller from route defaults + unset($route['_route'], $route['_controller']); + + //Generate url + $url = $this->router->generate($name, $route); + //Get first route from route collection if / path was not matched + } catch(ResourceNotFoundException $e) { + //Fetch all routes + //XXX: this method regenerate the Routing cache making apps very slow + //XXX: see https://github.com/symfony/symfony-docs/issues/6710 + //XXX: it should be fine to call it without referer and a / route + foreach($this->router->getRouteCollection() as $name => $route) { + //Return on first public route excluding logout one + if (!empty($name) && $name[0] != '_' && $name != $logout) { + break; + } + } + + //Bail out if no route found + if (!isset($name) || !isset($route)) { + throw new \RuntimeException('Unable to retrieve default route'); + } + + //Retrieve route defaults + $defaults = $route->getDefaults(); + + //Remove route and controller from route defaults + unset($defaults['_route'], $defaults['_controller']); + + //Generate url + $url = $this->router->generate($name, $defaults); + } + } + + //Return redirect response + return new RedirectResponse($url, 302); + } +} -- 2.41.1