Closed shairyar closed 8 years ago
Hi Shairyar, You'll need to provide some more info if you want help.
1) Can you explain your configuration a bit more? 2) Can you post some of the code which is relevant to the user? 3) What bundles you are using? 4) Have you looked at the user in the database to confirm data is correct?
Off the top of my head: i would say you are using the FOSUserBundle - correct? I too don't want a username and email. I fixed this by doing the following in my entity\user.php
/**
* @param string $username
*
* @return $this
*/
public function setUsername($username)
{
parent::setUsername($this->email);
return $this;
}
To solve the authenticated NO issue, i would say there could be an issue with your config or your authentication or your controller - hard to tell without code.
Hi @rwitchell,
Thanks for getting back, I am not using any 3rd party bundle other than oauth2 bundle. I am only having trouble first time when i register, once the user is registered and come through facebook again using the same user things work fine.
Here is my security.yml
security:
encoders:
# Our user class and the algorithm we'll use to encode passwords
# http://symfony.com/doc/current/book/security.html#encoding-the-user-s-password
AppBundle\Entity\User: bcrypt
providers:
# Simple example of loading users via Doctrine
# To load users from somewhere else: http://symfony.com/doc/current/cookbook/security/custom_provider.html
database_users:
entity: { class: AppBundle:User, property: username }
firewalls:
dev:
pattern: ^/(_(profiler|wdt|error)|css|images|js)/
security: false
main:
anonymous: ~
logout: ~
guard:
authenticators:
- app.form_login_authenticator
- app.facebook_authenticator
- app.linkedin_authenticator
# by default, use the start() function from FormLoginAuthenticator
entry_point: app.form_login_authenticator
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/admin/, roles: ROLE_ADMIN }
- { path: ^/candidate, roles: ROLE_JOBSEEKER }
Here is my FacebookConnectController
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\JobSeekerProfile;
use AppBundle\Entity\User;
use AppBundle\Form\JobSeekerRegistrationType;
use League\OAuth2\Client\Provider\FacebookUser;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class FacebookConnectController extends Controller
{
/**
* @Route("/connect/facebook", name="connect_facebook")
*/
public function connectFacebookAction(Request $request)
{
// redirect to Facebook
$facebookClient = $this->get('knpu.oauth2.registry')
->getClient('my_facebook_client');
return $facebookClient->redirect();
}
/**
* @Route("/connect/facebook-check", name="connect_facebook_check")
*/
public function connectFacebookActionCheck()
{
// will not be reached!
}
/**
* @Route("/connect/facebook/registration", name="connect_facebook_registration")
*/
public function finishRegistration(Request $request)
{
/** @var FacebookUser $facebookUser */
$facebookUser = $this->get('app.facebook_authenticator')
->getUserInfoFromSession($request);
if (!$facebookUser) {
throw $this->createNotFoundException('How did you get here without user information!?');
}
$user = new User();
$user->setFacebookId($facebookUser->getId());
$user->setUsername($facebookUser->getEmail());
$user->setIsActive('1');
$user->setRoles(array('ROLE_JOBSEEKER'));
$JS = new JobSeekerProfile();
$JS->setFirstName($facebookUser->getFirstName());
$JS->setLastName($facebookUser->getLastName());
$JS->setGender($facebookUser->getGender());
$JS->setCountry($facebookUser->getHometown());
$user->setJobSeekerProfile($JS);
$form = $this->createForm(JobSeekerRegistrationType::class, $user);
$form->handleRequest($request);
if ($form->isValid()) {
// encode the password manually
$plainPassword = $form['plainPassword']->getData();
$encodedPassword = $this->get('security.password_encoder')
->encodePassword($user, $plainPassword);
$user->setPassword($encodedPassword);
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->persist($JS);
$em->flush();
// remove the session information
$request->getSession()->remove('facebook_user');
// log the user in manually
$guardHandler = $this->container->get('security.authentication.guard_handler');
return $guardHandler->authenticateUserAndHandleSuccess(
$user,
$request,
$this->container->get('app.facebook_authenticator'),
'main' // the firewall key
);
}
return $this->render('AppBundle::registration.html.twig', array(
'form' => $form->createView()
));
}
}
Here is my User Entity
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class User implements UserInterface, AdvancedUserInterface
{
private $id;
private $username;
private $password;
private $roles = array();
private $isActive;
private $apiToken;
private $lastLoginTime;
private $facebookId;
private $linkedinId;
/**
* @var \AppBundle\Entity\JobSeekerProfile
*/
private $jobSeekerProfile;
public function __construct()
{
$this->apiToken = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
}
public function getId()
{
return $this->id;
}
public function getPassword()
{
return $this->password;
}
public function setPassword($password)
{
$this->password = $password;
}
/**
* Returns the roles or permissions granted to the user for security.
*/
public function getRoles()
{
$roles = $this->roles;
// guarantees that a user always has at least one role for security
if (empty($roles)) {
$roles[] = 'ROLE_JOBSEEKER';
}
return array_unique($roles);
}
public function setRoles($roles)
{
$this->roles = $roles;
}
/**
* Returns the salt that was originally used to encode the password.
*/
public function getSalt()
{
return;
}
public function getUsername()
{
return $this->username;
}
/**
* Set username
*
* @param string $username
*
* @return User
*/
public function setUsername($username)
{
$this->username = $username;
return $this;
}
/**
* Removes sensitive data from the user.
*/
public function eraseCredentials()
{
// if you had a plainPassword property, you'd nullify it here
// $this->plainPassword = null;
}
/**
* @param string $apiToken
*/
public function setApiToken($apiToken)
{
$this->apiToken = $apiToken;
}
public function setLastLoginTime(\DateTime $lastLoginTime)
{
$this->lastLoginTime = $lastLoginTime;
}
public function getFacebookId()
{
return $this->facebookId;
}
public function setFacebookId($facebookId)
{
$this->facebookId = $facebookId;
}
/**
* Get apiToken
*
* @return string
*/
public function getApiToken()
{
return $this->apiToken;
}
/**
* Get lastLoginTime
*
* @return \DateTime
*/
public function getLastLoginTime()
{
return $this->lastLoginTime;
}
/**
* Set linkedinId
*
* @param string $linkedinId
*
* @return User
*/
public function setLinkedinId($linkedinId)
{
$this->linkedinId = $linkedinId;
return $this;
}
/**
* Get linkedinId
*
* @return string
*/
public function getLinkedinId()
{
return $this->linkedinId;
}
public function isAccountNonExpired()
{
return true;
}
public function isAccountNonLocked()
{
return true;
}
public function isCredentialsNonExpired()
{
return true;
}
public function isEnabled()
{
return $this->isActive;
}
public function setIsActive($isActive)
{
$this->isActive = $isActive;
return $this;
}
public function getIsActive()
{
return $this->isActive;
}
public function setJobSeekerProfile(\AppBundle\Entity\JobSeekerProfile $jobSeekerProfile = null)
{
$this->jobSeekerProfile = $jobSeekerProfile;
$jobSeekerProfile->setJobSeekerUser($this);
return $this;
}
public function getJobSeekerProfile()
{
return $this->jobSeekerProfile;
}
}
Hmm, this is tricky. The biggest reason for the "Authenticated No" thing is that your user has no roles - in fact it's the only way that I'm aware of for this to happen. When you see "Authenticated No" - what roles does it show in the web debug toolbar / profiler? Your User
class looks correct - it looks like it always returns at least one role, but I still think this is the issue somehow.
The role is see is ROLE_JOBSEEKER
..
I think problem occurs when using AdvancedUserInterface
if I get rid of AdvancedUserInterface
from my User entity things start working fine, i am able to register the first time it self and Authenticated is Yes but the moment I put back AdvancedUserInterface
the registration process breaks down and i am not authenticated the first time. At the moment all i have in the methods of AdvancedUserInterface
is as following.
public function isAccountNonExpired()
{
return true;
}
public function isAccountNonLocked()
{
return true;
}
public function isCredentialsNonExpired()
{
return true;
}
public function isEnabled()
{
return $this->isActive;
}
Ah, nice detective work! If you simply return true
from isEnabled
, does that fix it (I imagine it does)? Also, can you double-check that isActive
is true
after you finish registration (right before you make the Guard call). I'm sure it is - but trying to find the issue :). Finally, does your User
class implement the SerializableInterface
? And if so, is the isActive
field included in the serialized data (it should be).
There are some pitfalls - especially when using AdvancedUserInterface - it may be one of those, or may be Guard related - I'm not sure yet :).
Thanks!
Hi,
Ah, nice detective work! If you simply return true from
isEnabled
, does that fix it (I imagine it does)?
Yes if I hardcode this inside the Entity it does fix the problem.
public function isEnabled()
{
return true;
}
Also, can you double-check that isActive is true after you finish registration (right before you make the Guard call).
I am already doing this as I am saving the isActive
value inside database
Finally, does your User class implement the SerializableInterface? And if so, is the isActive field included in the serialized data (it should be).
No I am not using SerializableInterface
@shairyar if you're able to post a small project with this issue, I can debug further. Unfortunately, I can't seem to repeat this locally, even if I use AdvancedUserInterface. Typically, this occurs because after you login, on the next request, this hasChangedMethod on your token returns false. In your case, somehow, the isEnabled
return value is changing - something related to how the User object is being serialized :/. It still may be a legitimate issue, but if it is, it's subtle.
I think we can close this issue for now, i will investigate more and create the small project if this issue resurface again. Many thanks for all the help.
Hi,
I am having a weird problem when I register the first time ever and then i fill up the registration password fields i get logged it but the profiler says "Authenticated NO" but if i log out and log back in using the same facebook account this time the Authenticated is YES.
There is one thing I changed to integrated it in current system
I am having hard time finding out why the first time Authenticated is No and then its Yes once i log out and log back in.