FOSUserBundle: Success target after password reset - symfony

After the user did reset his password using the password reset of FOSUserBundle, by default he is redirected to the FOSUserProfile.
I want to redirect to a different route.
Is this possible and if yes, how?

It can be done by creating a resetting subscriber:
namespace Acme\UserBundle\EventListener;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* Listener responsible to change the redirection at the end of the password resetting
*/
class PasswordResettingListener implements EventSubscriberInterface {
private $router;
public function __construct(UrlGeneratorInterface $router) {
$this->router = $router;
}
public static function getSubscribedEvents() {
return [
FOSUserEvents::RESETTING_RESET_SUCCESS => 'onPasswordResettingSuccess',
];
}
public function onPasswordResettingSuccess(FormEvent $event) {
$url = $this->router->generate('homepage');
$event->setResponse(new RedirectResponse($url));
}
}
And then registering it as a service with kernel.event_subscriber tag:
# src/Acme/UserBundle/Resources/config/services.yml
services:
acme_user.password_resetting:
class: Acme\UserBundle\EventListener\PasswordResettingListener
arguments: [ #router ]
tags:
- { name: kernel.event_subscriber }

In case you are not using the FOS user profile view, there is an ugly yet simple way:
Add in your app/config/routing.yml:
fos_user_profile_show:
path: /yourpath

Related

Cannot autowire service in Symfony 3.4 and FosUserBundle

I try to override REGISTRATION_SUCCESS in FosUserBundle to redirect the admin on user's list after register a new user.
So I have created a new event subscriber :
<?php
namespace AppBundle\EventListener;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Mailer\MailerInterface;
use FOS\UserBundle\Util\TokenGeneratorInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class RedirectAfterRegistrationSubscriber implements EventSubscriberInterface
{
private $mailer;
private $tokenGenerator;
private $router;
public function __construct(MailerInterface $mailer, TokenGeneratorInterface $tokenGenerator, UrlGeneratorInterface $router)
{
$this->mailer = $mailer;
$this->tokenGenerator = $tokenGenerator;
$this->router = $router;
}
public function onRegistrationSuccess(FormEvent $event)
{
$user = $event->getForm()->getData();
$user->setEnabled(false);
if (null === $user->getConfirmationToken()) {
$user->setConfirmationToken($this->tokenGenerator->generateToken());
}
$this->mailer->sendConfirmationEmailMessage($user);
$url = $this->router->generate('user_index');
$event->setResponse(new RedirectResponse($url));
}
public static function getSubscribedEvents()
{
return [
FOSUserEvents::REGISTRATION_SUCCESS => 'onRegistrationSuccess'
];
}
}
and the following service :
app.redirect_after_registration_subscriber:
class: AppBundle\EventListener\RedirectAfterRegistrationSubscriber
arguments: ['#fos_user.mailer', '#fos_user.util.token_generator', '#router']
tags:
- { name: kernel.event_subscriber }
I don't understand why this error appears :
Cannot autowire service "AppBundle\EventListener\RedirectAfterRegistrationSubscriber":
argument "$mailer" of method "__construct()" references interface
"FOS\UserBundle\Mailer\MailerInterface" but no such service exists. You should maybe alias
this interface to one of these existing services: "fos_user.mailer.default",
"fos_user.mailer.twig_swift", "fos_user.mailer.noop".
I suppose you are using autodiscovering of services. Something like:
# services.yaml
AppBundle\:
resource: '../src/'
...
So in addition to the #app.redirect_after_registration_subscriber that you define, Symfony defines another service with id #AppBundle\EventListener\RedirectAfterRegistrationSubscriber. Both point to AppBundle\EventListener\RedirectAfterRegistrationSubscriber class. Yet you configured the mailer parameter only for the first one.
The solution:
AppBundle\EventListener\RedirectAfterRegistrationSubscriber:
arguments: ['#fos_user.mailer', '#fos_user.util.token_generator', '#router']
tags:
- { name: kernel.event_subscriber }
With autowiring and autoconfigure you can even sypmlify to:
AppBundle\EventListener\RedirectAfterRegistrationSubscriber:
arguments:
$mailer: '#fos_user.mailer'

How to definitely disable registration in FOSUserBundle

In my project, I allow only one user to manage the content of the website. This user will be added using the command line at first.
Now, I want to get the registration action inaccessible and I don't know how?
Till now, I just put the ROLE_ADMIN in the access control for the route register to avoid that visitors can go throw it.
Any tips?
Take a look at the routing configuration imported from
vendor/friendsofsymfony/user-bundle/Resources/config/routing/all.xml
If you want just the basic security actions, just import
#FOSUserBundle/Resources/config/routing/security.xml
instead of
#FOSUserBundle/Resources/config/routing/all.xml
This way you can simply select which components (security, profile, resetting, change_password) you want to use or event import only specific routes from those components.
There are many ways to solve this issue. You can simply remove fos_user_registration_register route from routing.yml. Or use more complicated solution: set up event listener to FOS\UserBundle\FOSUserEvents::REGISTRATION_INITIALIZE event and redirect user to login page.
services.xml
<service id="app.registration.listener" class="AppBundle\EventListener\RegistrationListener">
<tag name="kernel.event_subscriber" />
<argument type="service" id="router" />
</service>
RegistrationListener.php
<?php
namespace AppBundle\EventListener;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\FOSUserEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class RegistrationListener implements EventSubscriberInterface
{
/**
* #var UrlGeneratorInterface
*/
private $router;
/**
* #param UrlGeneratorInterface $router
*/
public function __construct(UrlGeneratorInterface $router) {
$this->router = $router;
}
public static function getSubscribedEvents()
{
return [
FOSUserEvents::REGISTRATION_INITIALIZE => 'onRegistrationInitialize',
];
}
public function onRegistrationInitialize(GetResponseUserEvent $event)
{
$url = $this->router->generate('fos_user_security_login');
$response = new RedirectResponse($url);
$event->setResponse($response);
}
}
You can just change app/config/security.yml:
- { path: ^/register, role: ROLE_ADMIN }
Change from the default (IS_AUTHENTICATED_ANONYMOUSLY) to ROLE_ADMIN and it will stop allowing anonymous users from getting to the /register form.
Another simple solution (the one I used) is to overwrite the registerAction() default FOSUserBundle controller method:
namespace Acme\UserBundle\Controller;
use FOS\UserBundle\Controller\RegistrationController as FOSRegistrationController;
use Symfony\Component\HttpFoundation\Request;
class RegistrationController extends FOSRegistrationController
{
public function registerAction(Request $request)
{
return $this->redirectToRoute('getStarted', array(), 301);
}
}
Doing this will leave active other routes, as the confirmation page.
I simply overwrote the register action and redirect the user to my first registration page (getStarted).
If you use the JMSSecurityExtraBundle you can use the denyAll directive like so:
- { path: ^/register, access: denyAll }
This is how I solve this issue...
First you have to define your listener in the services.yml file:
services:
registrationListner:
class: App\YourBundle\Listener\RegistrationListener
arguments: [#service_container]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest}
Then create your class RegistrationListener:
<?php
namespace App\YourBundle\Listener;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
class RegistrationListener
{
private $router;
public function __construct(ContainerInterface $container){
$this->router = $container->get('router');
}
public function onKernelRequest(GetResponseEvent $event)
{
$route = $event->getRequest()->attributes->get('_route');
if ($route == 'fos_user_registration_register') {
//here we're gonna to redirect to you_route for example, I guess in the most cases it will be the index...
$event->setResponse(new RedirectResponse($this->router->generate('your_route')));
}
}
}
Hope it helps.
You can try to change your routing.yml
fos_user_registration_register:
path: /register{trailingSlash}
defaults: { _controller: AcmeBundle:Default:register, trailingSlash : "/" }
requirements: { trailingSlash : "[/]{0,1}" }
And in your DefaultController
public function registerAction(Request $request)
{
return $this->redirectToRoute('404OrWhatYouWant');
}

FOSUserBundle: Registration redirect if logged in

I was wondering what would be the best method to redirect a user who is ALREADY LOGGED IN if they try and access the registration page.
I would prefer a method that does not require me overriding the registration controller simply to implement a login check & redirect.
I looked at the registration initialization event but I don't know how to initiate the redirect since there doesn't seem to be a way to set the event response via the UserEvent class.
Thanks
I use something like the following..
namespace Acme\UserBundle\EventSubscriber;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\FOSUserEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;
class FOSUserSubscriber implements EventSubscriberInterface
{
protected $router;
protected $securityContext;
public function __construct(
UrlGeneratorInterface $router,
SecurityContextInterface $securityContext
)
{
$this->router = $router;
$this->securityContext = $securityContext;
}
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::REGISTRATION_INITIALIZE => 'forwardToRouteIfUser',
);
}
public function forwardToRouteIfUser(GetResponseUserEvent $event)
{
if (!$this->securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
return;
}
$url = $this->router->generate('acme_the_route_to_redirect_to');
$response = new RedirectResponse($url);
$event->setResponse($response);
}
}
With
parameters:
acme_user.subscriber.fos_user.class:
Acme\UserBundle\EventSubscriber\FOSUserSubscriber
services:
acme_user.subscriber.fos_user:
class: %acme_user.subscriber.fos_user.class%
arguments:
- #router
- #security.context
tags:
- { name: kernel.event_subscriber

Login EventListener not firing on production side

I have an event listener that should fire when a user logs in in my Symfony setup.
I have the following in my services.yml
...
d_user.login_listener:
class: D\UserBundle\EventListener\LoginListener
arguments: []
tags:
- { name: 'kernel.event_subscriber', event: 'security.interactive_login' }
and in my login listener I simply have this:
<?php
namespace D\UserBundle\EventListener;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class LoginListener implements EventSubscriberInterface
{
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
echo 'user logged in';
}
public static function getSubscribedEvents()
{
return array(
// must be registered before the default Locale listener
'security.interactive_login' => array(array('onSecurityInteractiveLogin', 18))
);
}
}
On my dev server I correctly see the text "user logged in" before redirection, but on my production server it just logs in without the event firing. I'm modifying this later to set a session var on user login. I just need to get the method called.
Any advice? I've tried clearing the cache for prod and dev on my production environment, but that didn't help.
Debugging with echo is discouraged. If you want an output, use the logger!
namespace D\UserBundle\EventListener;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class LoginListener implements EventSubscriberInterface
{
private $logger;
private $router;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
$this->logger->info('user logged in');
}
public static function getSubscribedEvents()
{
return array(
// must be registered before the default Locale listener
'security.interactive_login' => array(array('onSecurityInteractiveLogin', 18))
);
}
}
and inject the logger in your service defintion, preferrable with a nice channel name:
d_user.login_listener:
class: D\UserBundle\EventListener\LoginListener
arguments: [#logger]
tags:
- { name: 'kernel.event_subscriber', event: 'security.interactive_login' }
- { name: monolog.logger, channel: d_user }

Symfony2: check-email after registration

First time I'm posting a message in this forum, which I use regularly. I use FOSUserbundle in my Symfony2 application to manage users. I activated the sending of the email confirmation when users create an account by the following thing:
fos_user:
registration:
confirmation:
enabled: true
It works very well: the email is sent successfully. I am redirected to the page /check-email that says that this email has been sent. However, I would like to change the redirection : I would like to be redirected to my index page and not to /check-email. So I did my research and I knew he had to go through the FOSUserBundle events (list here).
What I did :
class RegistrationListener implements EventSubscriberInterface {
private $router;
public function __construct(UrlGeneratorInterface $router) {
$this->router = $router;
}
public static function getSubscribedEvents() {
return array(
FOSUserEvents::REGISTRATION_CONFIRM => 'onRegistrationConfirm');
}
public function onRegistrationConfirm(FormEvent $event) {
$url = $this->router->generate('listeArticlesAccueil');
$event->setResponse(new RedirectResponse($url));
}
}
and services.yml
services:
listener_user.registration_listener:
class: My\Soft\UserBundle\EventListener\RegistrationListener
arguments: [#router]
tags:
- { name: kernel.event_subscriber }
The problem is that every time I am redirected to the page /check-email. I therefore told me that it was probably the wrong event. So I also tried REGISTRATION_SUCCESS. But nothing changes. So either I have not used the right event, or I'm doing something wrong.
In either case, I hope you can help me !
Thanks a lot and sorry for my bad english ;)
I know that this question has been posted a long time ago, but i found a solution and I would like to share it to others that have the same issue.
In this case, the event that you should use is REGISTRATION_SUCCESS.
You have to prioritize the listener REGISTRATION_SUCCESS to be called before FOS\UserBundle\EventListener\EmailConfirmationListener::onRegistrationSuccess like this:
public static function getSubscribedEvents()
{
return [
FOSUserEvents::REGISTRATION_SUCCESS => [
['onRegistrationSuccess', -10],
],
];
}
If you don't do it, EmailConfirmationListener will be called earlier and you will be redirected to fos_user_registration_check_email route.
Here is what I did:
class RedirectAfterRegistrationSubscriber implements EventSubscriberInterface
{
private $router;
public function __construct(RouterInterface $router)
{
$this->router = $router;
}
public function onRegistrationSuccess(FormEvent $event)
{
$event->stopPropagation();
$url = $this->router->generate('homepage');
$response = new RedirectResponse($url);
$event->setResponse($response);
}
public static function getSubscribedEvents()
{
return [
FOSUserEvents::REGISTRATION_SUCCESS => ['onRegistrationSuccess',-10],
];
}
}
And in app/services.yml:
app.redirect_after_registration_subscriber:
class: AppBundle\EventListener\RedirectAfterRegistrationSubscriber
arguments: ['#router']
tags:
- { name: kernel.event_subscriber }
I hope this helps.
I would bet on REGISTRATION_SUCCESS.
The doc (https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/FOSUserEvents.php) says
that this event allows to set the response.
REGISTRATION_CONFIRM only allows to access the user
Instead of that use REGISTRATION_CONFIRM.
Here is the complete code for the event listener:
/**
* Description of RegisterationConfirmListener
*
* #author imran
*/
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\GetResponseUserEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* Description of RegisterationConfirmListener
*
* #author imran
*/
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\GetResponseUserEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* Listener responsible to change the redirection at the end of the password resetting
*/
class RegisterationConfirmListener implements EventSubscriberInterface {
private $router;
public function __construct(UrlGeneratorInterface $router) {
$this->router = $router;
}
public static function getSubscribedEvents() {
return [
FOSUserEvents::REGISTRATION_CONFIRM => 'onRegisterationConfirm',
];
}
public function onRegisterationConfirm(GetResponseUserEvent $event) {
$url = $this->router->generate('home');
$event->setResponse(new RedirectResponse($url));
}
}
For Services.yml:
app_user.registeration_confirmed:
class: Wishlocker\AppBundle\EventListener\RegisterationConfirmListener
arguments: [ #router ]
tags:
- { name: kernel.event_subscriber }

Resources