Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
TRACK

Symfony 3 >

TargetPathTrait: Redirect to Previous Page

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

We now have control over where the user goes after registering. But... it's not as awesome as it could be. Let me show you why.

First, look at my app/config/security.yml file. In order to access any URL that start with /admin, you need to be logged in. For example, if I go to /admin/genus, it sends me to the login page.

Thanks to Symfony's form_login system, if we logged in, it would automatically redirect us back to /admin/genus... which is awesome! That's clearly where the user wants to go.

But what if I instead clicked a link to register and submitted that form? Shouldn't that also redirect me back to /admin/genus after? Yea, that would be way better: I want to keep the user's experience really smooth.

How can we do this?

Using TargetPathTrait

Guess what? It's almost effortless, thanks to a trait that was added in Symfony 3.1: TargetPathTrait. In your subscriber, use TargetPathTrait. Then, down in onRegistrationSuccess, add $url = $this->getTargetPath() - a method provided by that trait. Pass this $event->getRequest()->getSession() and for the "provider key" argument, pass main. Provider key is a fancy term for your firewall's name.

<?php
... lines 2 - 11
class RedirectAfterRegistrationSubscriber implements EventSubscriberInterface
{
use TargetPathTrait;
... lines 15 - 22
public function onRegistrationSuccess(FormEvent $event)
{
// main is your firewall's name
$url = $this->getTargetPath($event->getRequest()->getSession(), 'main');
... lines 27 - 33
}
... lines 35 - 41
}

What's going on here? Well, whenever you try to access a secured page anonymously, Symfony stores that URL somewhere in the session before redirecting you to the login page. Then form_login uses that to redirect you after you authenticate. The TargetPathTrait is just a shortcut for us to read that same key from the session.

If $url is empty - it means the user went directly to the registration page. No worries! Just send them to the homepage.

<?php
... lines 2 - 11
class RedirectAfterRegistrationSubscriber implements EventSubscriberInterface
{
... lines 14 - 22
public function onRegistrationSuccess(FormEvent $event)
{
... lines 25 - 27
if (!$url) {
$url = $this->router->generate('homepage');
}
... lines 31 - 33
}
... lines 35 - 41
}

Let's try the entire flow. I'll go back to /admin/genus: it redirects me to the login page and sets that session key behind the scenes. Then, I'll manually type in /register - but pretend like we clicked a link. Register as aquanaut6, password turtles.

Booya! Logged in and on the /admin/genus page. That's a kick butt registration form.

Leave a comment!

12
Login or Register to join the conversation
Dung L. Avatar
Dung L. Avatar Dung L. | posted 3 years ago

Hi KNP,

I would like to create button in Twig to go back to whatever the previous page is and I found this code: "Go Back To Previous Page" Unfortunately tested it does not work in Symfony 4 default twig version - it will only return url of the current page. (source: https://stackoverflow.com/q....

How do we do this with Twig framework, is it possible?

Thank you!

Reply

Hey Dung L.

Hmm, I don't know why it's not working, getting the referer from the request seems like the right way to do what you want, but just be aware of it might be null or a hacky user could modify it (of course, it would only affect himself). Probably what you want is "breadcrumbs" https://github.com/whiteoct...

Cheers!

Reply
Dung L. Avatar

Excellent, another bundle (more service :) means for food for knowledge and more power, I will try it out and Thanks Diego!

Reply
Dung L. Avatar
Dung L. Avatar Dung L. | Dung L. | posted 3 years ago | edited

Good Morning Dung L.

I have successfully implemented "breadcrumbs". And in regard to Twig template's output expression {{ app.request.headers.get('referer') }} the reason it did not work was because had attribute rel="noopener noreferrer" in my anchor tag - it works now after removing "rel"

Thank you for your pointers!

1 Reply
Mixa S. Avatar
Mixa S. Avatar Mixa S. | posted 5 years ago

Hello KNP Team and thanks for your videos!

By the way, how can I handle ALREADY logged-in user if he goes to /login page?
In my case he sees login form still but has logged-in status in web-profiler bar.

Reply

Hey Lopoi,

Good question, the default behavior is to redirect already logged-in users to the homepage (or any other page that makes more sense). So yeah, it makes sense do not show login page for those users. But there's a subtle difference: if you use "remember me" functionality ( see https://symfony.com/doc/cur... ) - then we do need to show login form for those users, i.e. users who authenticated as IS_AUTHENTICATED_REMEMBERED so that they can authenticate as IS_AUTHENTICATED_FULLY. IN some parts of our application we do want to require IS_AUTHENTICATED_FULLY from our users - it makes sense for pages that need extra security. For example, on KnpU we do require IS_AUTHENTICATED_FULLY to view invoices. That means if user has IS_AUTHENTICATED_REMEMBERED only and trying to view his invoice - he we'll be redirected to the /login page to log in again as IS_AUTHENTICATED_FULLY and after successful login he will be redirected back to the invoice page.

Cheers!

1 Reply
Mixa S. Avatar
Mixa S. Avatar Mixa S. | Victor | posted 5 years ago | edited

Hey victor ,

looks like in SF4 the easiest way to redirect already logged-in user to route - to use guard system.
Or may be there is some event to intercept?

I tried this https://stackoverflow.com/questions/49585780/symfony-redirect-user-already-logged-in
solution but had error :


request.CRITICAL: Uncaught PHP Exception Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException: "The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL." at /home/vagrant/code/tests/sf4/fosuser-starter-kit/vendor/symfony/security/Core/Authorization/AuthorizationChecker.php line 49 {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL. at /home/vagrant/code/tests/sf4/fosuser-starter-kit/vendor/symfony/security/Core/Authorization/AuthorizationChecker.php:49)"} []
[2018-08-13 15:15:07] request.CRITICAL: Exception thrown when handling an exception (Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException: The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL. at /home/vagrant/code/tests/sf4/fosuser-starter-kit/vendor/symfony/security/Core/Authorization/AuthorizationChecker.php line 49) {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL. at /home/vagrant/code/tests/sf4/fosuser-starter-kit/vendor/symfony/security/Core/Authorization/AuthorizationChecker.php:49)"} []
[2018-08-13 15:15:07] php.CRITICAL: Uncaught Exception: The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL. at /home/vagrant/code/tests/sf4/fosuser-starter-kit/vendor/symfony/security/Core/Authorization/AuthorizationChecker.php:49, Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL. at /home/vagrant/code/tests/sf4/fosuser-starter-kit/vendor/symfony/security/Core/Authorization/AuthorizationChecker.php:49)"} []
[2018-08-13 15:15:07] request.CRITICAL: Uncaught PHP Exception Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException: "The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL." at /home/vagrant/code/tests/sf4/fosuser-starter-kit/vendor/symfony/security/Core/Authorization/AuthorizationChecker.php line 49 {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL. at /home/vagrant/code/tests/sf4/fosuser-starter-kit/vendor/symfony/security/Core/Authorization/AuthorizationChecker.php:49, Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException(code: 0): The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL. at /home/vagrant/code/tests/sf4/fosuser-starter-kit/vendor/symfony/security/Core/Authorization/AuthorizationChecker.php:49)"} []

Please advise.

Reply

Hey Lopoi,

Yeah, if we're talking about FOSUserBundle - I think the easier way to do so is to add an even listener as in example you provided. What about the error, could you show the code that causes those errors?

Cheers!

1 Reply
Mixa S. Avatar
Mixa S. Avatar Mixa S. | Victor | posted 5 years ago | edited

victor , thanks for your quick reply!

I used exact code from SO link above and codebase from this KNP tutorial.

Error messages attached in this thread.

Actually I changed their code a little and replied also at stackoverflow https://stackoverflow.com/q...

Now all works as expected using kernel events. So it is not a problem anymore.
Thanks for your attention to my issue!

Reply

Hey Lopoi,

I'm glad you fixed the problem by yourself, it's even better than to get a ready-to-use solution from somebody. Great work!

Cheers!

Reply
Default user avatar
Default user avatar Yasiru Nilan | posted 5 years ago

How to do this redirecting to How to do this redirecting to the previous page with login controller.It doesn't have event listeners like registration controller?the previous page with login controller.It doesn't have event listeners like registration controller?

Reply

Hey Yasiru Nilan!

Great question! If you're using FOSUserBundle in the "normal" way, then you are using the "form_login" mechanism in security.yml. This login system *automatically* redirects back to the previous page, without you needing to do *any* work. This feature actually doesn't come from FOSUserBundle, but is just part of Symfony's core. So, it should automatically work how you want it to. But, here is more information about how to customize where it redirects: https://symfony.com/doc/cur...

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.3.*", // v3.3.18
        "doctrine/orm": "^2.5", // v2.7.0
        "doctrine/doctrine-bundle": "^1.6", // 1.10.3
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.5
        "symfony/swiftmailer-bundle": "^2.3", // v2.5.4
        "symfony/monolog-bundle": "^2.8", // v2.12.1
        "symfony/polyfill-apcu": "^1.0", // v1.3.0
        "sensio/distribution-bundle": "^5.0", // v5.0.18
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.25
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "knplabs/knp-markdown-bundle": "^1.4", // 1.5.1
        "doctrine/doctrine-migrations-bundle": "^1.1", // v1.3.2
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "friendsofsymfony/user-bundle": "^2.0" // v2.0.0
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.1.4
        "symfony/phpunit-bridge": "^3.0", // v3.2.7
        "nelmio/alice": "^2.1", // v2.3.1
        "doctrine/doctrine-fixtures-bundle": "^2.3", // v2.4.1
        "symfony/web-server-bundle": "^3.3"
    }
}
userVoice