I'm using FOSUserBundle together with NnmMultiUserBundle.
When a user register, using my form_handler, the User entity is created, and should automatically login this new user.
I haven't been able to make that automatic login works.
My Controller:
public function registerAction()
{
$discriminator = $this->container->get('nmn_user_discriminator');
$discriminator->setClass('Travelyo\UserBundle\Entity\UserFrontend');
$form = $discriminator->getRegistrationForm();
//$form = $this->container->get('fos_user.registration.form');
$formHandler = $this->container->get('fos_user.registration.form.handler');
$confirmationEnabled = $this->container->getParameter('fos_user.registration.confirmation.enabled');
$process = $formHandler->process($confirmationEnabled, array(User::ROLE_CUSTOMER));
if ($process) {
$user = $form->getData();
if ($confirmationEnabled) {
$this->container->get('session')->set('fos_user_send_confirmation_email/email', $user->getEmail());
$route = 'fos_frontend_registration_check_email';
} else {
$this->authenticateUser($user);
$route = 'fos_frontend_registration_confirmed';
}
$this->setFlash('fos_user_success', 'registration.flash.user_created');
$url = $this->container->get('router')->generate($route);
return new RedirectResponse($url);
}
return $this->container->get('templating')->renderResponse('TravelyoUserBundle:Registration:user_frontend.form.html.' . $this->getEngine(), array('form' => $form->createView(),));
}
Athenticate method:
protected function authenticateUser(UserInterface $user)
{
try {
$this->container->get('fos_user.user_checker')->checkPostAuth($user);
} catch (AccountStatusException $e) {
// Don't authenticate locked, disabled or expired users
return;
}
$providerKey = $this->container->getParameter('fos_user.firewall_name');
$token = new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());
$this->container->get('security.context')->setToken($token);
}
After calling athenticate the controller redirects to ConfirmedAction, where it tries to get the "logged in" user:
public function confirmedAction()
{
$user = $this->container->get('security.context')->getToken()->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
return $this->container->get('templating')->renderResponse('FOSUserBundle:Registration:confirmed.html.'.$this->getEngine(), array(
'user' => $user,
));
}
Error message:
Fatal error: Call to a member function getUser() on a non-object in /Data/Web/Local/travelyo/vendor/bundles/FOS/UserBundle/Controller/RegistrationController.php on line 115
If I then try to login using the login form it works fine (meaning that the creation of the user is working). But I can't understand why this token cannot be retrieved from security.context.
Security context is (as described in symfony 2 doc) not shared across firewall.
My registration form was in the "public firewall" => /register.
When authenticating the user (right after the user is registered), the token is saved for the public security.context.
I was then redirected to my actual "account" firewall => /account, and no token was found in the security.context as the token had never been defined for that firewall.
In order to solve it I simply moved my registration process under the same firewall, and it now works like a charm.
But I would still assume it should be possible to set a token for another security.context, if anyone know how it might be useful.
Thanks!
Related
I use FOSUserBundle for my User Authentication
I have a controller, let's call it adminController which is reserved for User granted User::ADMIN_ROLE
Everything works fine but I have an error when I try to write my functional Test
Inside my AdminControllerTest I have a method that try to test a page that need User::ADMIN_ROLE
My testAdminAccess() method
public function testAdminAccess()
{
$session = $this->client->getContainer()->get('session');
// the firewall context defaults to the firewall name
= 'main';
$user = $this->getUserByUsername('admin#yopmail.com');
$token = new UsernamePasswordToken($user, null, $firewallContext, $user->getRoles());
$session->set('_security_'.$firewallContext, serialize($token));
$session->save();
$cookie = new Cookie($session->getName(), $session->getId());
$this->client->getCookieJar()->set($cookie);
$this->client->followRedirects();
$crawler = $this->client->request(
'GET',
'http://localhost/admin'
);
dump($crawler);
}
I'm always redirected to my login page
How can I keep the session to access some page that's protected by a specific Role?
What I'm already tried:
http://kristiankaa.dk/symfony-authentication-controller-testing
How to log in User in Session within a Functional Test in Symfony 2.3?
https://symfony-docs-zh-cn.readthedocs.io/cookbook/testing/simulating_authentication.html
https://symfony.com/doc/2.6/cookbook/testing/simulating_authentication.html
How to programmatically login/authenticate a user?
I'm using Symfony version 3.4
The best is to login the user normally submitting the username and password like a standard user would do, I use a function like this (adapt your paths):
/**
* Log the test user for the connected tests.
*/
public function login(string $username = null, string $password = null): KernelBrowser
{
$client = static::createClient();
// Login page
$client->request('GET', '/en/login/');
$this->assertTrue($kernelBrowser->getResponse()->isOk());
// Auth
$token = $client->getContainer()->get('security.csrf.token_manager')->getToken('authenticate');
$client->request('POST', '/login_check', [
'_csrf_token' => $token,
'_username' => $username ?? 'test',
'_password' => $password ?? 'test',
'_remember_me' => 'on',
]);
$this->assertTrue($client->getResponse()->isRedirect());
$client->followRedirect();
return $client;
}
I know that fosUserBundle from Symfony can send EmailConfirmation automactly, just adding:
fos_user:
# ...
registration:
confirmation:
enabled: true
but i have my own register's form in my own controller. (I am NOT using register's form of FOSUSER). and i don't know how to send an emailconfirmation when an user register in my system.
these are my register's functions I am using:
public function index(Request $request)
{
$customer = new Customer();
$form = $this->createForm(CustomerType::class, $customer);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$pass = $form->get('password')->getData();
$email = $form->get('email')->getData();
$this->register($email, $email, $pass);
$em->persist($customer);
$em->flush($customer);
header("Refresh:0");
}
return $this->render('backend/customer/customer_register.html.twig', array('form' => $form->createView()));
}
and this Auxiliar Function:
private function register($email, $username, $password)
{
$userManager = $this->get('fos_user.user_manager');
$email_exist = $userManager->findUserByEmail($email);
if ($email_exist) {
return false;
}
$user = $userManager->createUser();
$user->setUsername($username);
$user->setEmail($email);
$user->setEmailCanonical($email);
$user->setEnabled(1);
$user->setPlainPassword($password);
$user->addRole('ROLE_CUSTOMER');
$userManager->updateUser($user);
return true;
}
I have tried using
$confirmationEnabled = $this->container->getParameter('fos_user.registration.confirmation.enabled');
but doesn't work
Please, I don't know how to start. it is neccessary to have any configuration of swift mailer?
if someone can help me I would appreciate it very much
Thanks, Thank you very much
You can take a look at the code used in FOSuserbundle at
Controller/RegistrationController::registerAction()
dispatches an event FOSUserEvents::REGISTRATION_SUCCESS which calls the function
EventListener/EmailConfirmationListener::onRegistrationSuccess()
It generates a token and set it to the user Entity $user->setConfirmationToken($this->tokenGenerator->generateToken()); then sends the email $this->mailer->sendConfirmationEmailMessage($user);
note the mailer is instance of FOS\UserBundle\Mailer\MailerInterface
and the token generator FOS\UserBundle\Util\TokenGeneratorInterface
I have two accounts one is client account and another is admin account. Client login to his account to edit profile and submit to admin approve. the problem when admin approve his updating then click submit then in client account reload page and have problem with message too many redirection.
Below is my code:
/**
* #Route("/client/personal-information", name="client_personal_info_page")
* #Template("FrontendBundle:ClientPanel:personal_info.html.twig")
*/
public function clientPersonalInfo(Request $request)
{
$user = $this->getUser();
$form = $this->createForm(ChangePersonalInfoFormType::class);
$form->setData($user);
$form->handleRequest($request);
if ($form->isValid()) {
$user = $form->getData();
$idCardPictureFront = $form->get('idCardPictureFront')->getData();
$idCardPictureBack = $form->get('idCardPictureBack')->getData();
$accountDocument = $form->get('accountDocument')->getData();
if ($idCardPictureFront != null) {
$file = new Media($idCardPictureFront);
$this->persistAndFlush($file);
$user->setIdCardPictureFront($file);
}
if ($idCardPictureBack != null) {
$file = new Media($idCardPictureBack);
$this->persistAndFlush($file);
$user->setIdCardPictureBack($file);
}
if ($accountDocument != null) {
$file = new Media($accountDocument);
$this->persistAndFlush($file);
$user->setAccountDocument($file);
}
if ($form->get('otherCountryCode')->getData() != null) {
$phnoneNumber = $form->get('otherCountryCode')->getData().'-'.
$form->get('phoneNumber')->getData();
$user->setPhoneNumber($phnoneNumber);
}
$user->setStatus(AccountStatus::PENDING_OPENING);
$user->setPendingType(PendingType::ACCOUNT_UPDATE);
$this->addLog(
$this->moduleName,
LogAction::UPDATE,
'User update personal information',
$user->getId()
);
$this->msgSuccess('frontend.client.panel.personal_info_updated');
$this->persistAndFlush($user);
return $this->redirect($request->getUri());
}
return $this->getResponseParameters([
'form' => $form->createView(),
'user' => $user,
]);
}
Nice to meet you.
I'm developping with Symfony 3.1.3 and I'm using the security system offered by the framework, no FOSUser neither Guard.
I have in my controller the typical function login:
public function loginAction(Request $request)
{
// This works
$authenticationUtils = $this->get('security.authentication_utils');
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render(
'security/loginForm_old.html.twig',
array(
// last username entered by the user
'last_username' => $lastUsername,
'error' => $error,
)
);
}
And I want to check if the user has activated his account. In the entity User I have the isActive attribute set to false by default and only with the link into the registration email is setted to true.
I have been searching for this issue without results and I'm sure this is something very common, everybody wants to check if the user's email is a good one.
Thanks.
Lets assume that you have an RegistrationController.php class where you store all code that manage about user's registration.
Create a function which sends email to user after registration:
public function sendConfirmationEmailMessage(User $user)
{
$confirmationToken = $user->getConfirmationToken();
$username = $user->getUsername();
$subject = 'Account activation';
$email = $user->getEmail();
$renderedTemplate = $this->templating->render('AppBundle:Emails:registration.html.twig', array(
'username' => $username,
'confirmationToken' => $confirmationToken
));
$message = \Swift_Message::newInstance()
->setSubject($subject)
->setFrom(MAILER_FROM)
->setReplyTo(MAILER_FROM)
->setTo($email)
->setBody($renderedTemplate, "text/html");
$this->mailer->send($message);
}
Create a route associated with function which takes an generated token as argument, then search user by that token and activate if user exist:
/**
* #Route("user/activate/{token}")
*/
public function confirmAction(Request $request, $token)
{
$em = $this->getDoctrine()->getManager();
$repository = $em->getRepository('AppBundle:User');
$user = $repository->findUserByConfirmationToken($token);
if (!$user)
{
throw $this->createNotFoundException('We couldn\'t find an account for that confirmation token');
}
$user->setConfirmationToken(null);
$user->setEnabled(true);
$em->persist($user);
$em->flush();
return $this->redirectToRoute('user_registration_confirmed');
}
Then when you have a function which actually registers the user you call the sendConfirmationEmailMessage as shown below:
public function registerAction(Request $request)
{
/* All the logic goes here: form validation, creating new user */
/* $user is created user */
sendConfirmationEmailMessage($user);
}
Anyway if isActive() function return false Symfony security system will prevent you from login. Your User entity should implement UserInterface.
I'm trying to make a symfony2 login that makes a user provide 3 credentials to login, e.g.
username
regnumber
password.
I'm using a custom entry provider, form the book. in this there is a class
public function loadUserByUsername($username)
{
$q = $this
->createQueryBuilder('u')
->where('u.username = :username')
->setParameter('username', $username)
->getQuery();
try {
// The Query::getSingleResult() method throws an exception
// if there is no record matching the criteria.
$user = $q->getSingleResult();
} catch (NoResultException $e) {
$message = sprintf(
'Unable to find an active User "%s".',
$username
);
throw new UsernameNotFoundException($message, 0, $e);
}
return $user;
}
Is there a way to pass more variables to this method e.g. loadUserByUsername($username, $regnumer)
I could then query for the extra data,
does anyone have any advice?
thanks in advance.