HybridAuth 2 ライブラリ用に独自の Symfony 2 認証プロバイダーを作成しました。認証プロセスは正常に機能しますが、ユーザーが正常に認証された後、ページが更新され、ユーザー プロバイダーで refreshUser() が呼び出されると getId() メソッドが返されます。 0 (ゼロ)。refreshUser() メソッドの先頭に var_dump($user) を配置すると、id パラメータが 1 (ゼロではない!!) に設定された認証済みユーザー オブジェクトが表示されますが、getId() メソッドは引き続きゼロを返します。私の ORM エンティティ オブジェクトでは、ユーザーの getId メソッドが $this->id を返します。
他のプロバイダーを使用すると問題なく動作しますが、このプロバイダーでのみユーザー ID がゼロになります。
認証プロバイダーで var_dump($user->getId()) を試行すると、トークンが返される直前に、ユーザー ID が 1 と表示されます。
何が間違っているのかわかりません...
@edit: コードは次のとおりです。
データベースから (「user_provider」タブから) ユーザーをロードするユーザー プロバイダー。ユーザーと OneToOne の関係があり、getUser() メソッドでユーザー オブジェクトを返します。
/**
* {@inheritdoc}
*/
public function loadUserByHybridAuthUserResponse($providerId, $providedId)
{
$userProvider = $this->userProviderManager->findOneByProvidedId($providerId, $providedId);
if (null === $userProvider) {
throw new AccountNotLinkedException(
sprintf('Your %s account is not linked to any account.', ucfirst($providerId))
);
}
$user = $userProvider->getUser();
return $user;
}
認証プロバイダー:
/**
* {@inheritDoc}
*/
public function authenticate(TokenInterface $token)
{
if (! $this->supports($token)) {
return null;
}
$provider = $token->getProviderAdapter();
$userId = $token->getUser();
try {
$user = $this->userProvider->loadUserByHybridAuthUserResponse($provider, $userId);
} catch (AccountNotLinkedException $e) {
$e->setProviderAdapter($token->getProviderAdapter());
throw $e;
}
// Try to authenticate user
$authenticatedToken = new HybridAuthToken($provider, $user, $user->getRoles());
$this->userChecker->checkPostAuth($user);
return $authenticatedToken;
}
認証トークン:
/**
* HybridAuth authentication token.
*/
class HybridAuthToken extends AbstractToken
{
/**
* @var string
*/
private $providerAdapter;
/**
* Constructor.
*
* @param string $providerAdapter The HybridAuth provider adapter name
* @param string $user The provided user identifier, or a UserInterface instance
* or an object implementing a __toString method.
* @param array $roles An array of roles
*/
public function __construct($providerAdapter, $user, array $roles = array())
{
parent::__construct($roles);
$this->providerAdapter = $providerAdapter;
$this->setUser($user);
parent::setAuthenticated(count($roles) > 0);
}
/**
* {@inheritDoc}
*/
public function getCredentials()
{
return '';
}
/**
* Return the HybridAuth provider adapter name.
*
* @return string
*/
public function getProviderAdapter()
{
return $this->providerAdapter;
}
/**
* {@inheritDoc}
*/
public function serialize()
{
return serialize(array(
$this->providerAdapter,
parent::serialize()
));
}
/**
* {@inheritDoc}
*/
public function unserialize($serialized)
{
list(
$this->providerAdapter,
$parent,
) = unserialize($serialized);
parent::unserialize($parent);
}
}
ユーザー プロバイダー エンティティ ("user_provider" mysql テーブル):
/**
* @ORM\Entity
* @ORM\Table("user_provider")
*/
class UserProvider implements UserProviderInterface
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*
* @access protected
* @var integer
*/
protected $id;
/**
* @ORM\OneToOne(targetEntity="Security\UserBundle\Entity\User")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*
* @access protected
* @var UserInterface
*/
protected $user;
/**
* @ORM\Column(type="string", length=50, name="provider_id")
*
* @access protected
* @var integer
*/
protected $providerId;
/**
* @ORM\Column(type="string", length=255, name="provided_id")
*
* @access protected
* @var integer
*/
protected $providedId;
/**
* {@inheritDoc}
*/
public function getId()
{
return $this->id;
}
/**
* {@inheritDoc}
*/
public function getUser()
{
return $this->user;
}
/**
* {@inheritDoc}
*/
public function setUser(UserInterface $user)
{
$this->user = $user;
return $this;
}
/**
* {@inheritDoc}
*/
public function getProviderId()
{
return $this->providerId;
}
/**
* {@inheritDoc}
*/
public function setProviderId($providerId)
{
$this->providerId = $providerId;
return $this;
}
/**
* {@inheritDoc}
*/
public function getProvidedId()
{
return $this->providedId;
}
/**
* {@inheritDoc}
*/
public function setProvidedId($providedId)
{
$this->providedId = $providedId;
return $this;
}
}
ユーザー エンティティ ("user" mysql テーブル):
/**
* @ORM\Entity
* @ORM\Table("user")
*/
class User implements UserInterface
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*
* @access protected
* @var integer
*/
protected $id;
/**
* @ORM\Column(type="string", length=255)
*
* @access protected
* @var string
*/
protected $email;
/**
* @ORM\Column(name="email_canonical", type="string", length=255, unique=true)
*
* @access protected
* @var string
*/
protected $emailCanonical;
/**
* @access protected
* @var string
*/
protected $plainPassword;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*
* @access protected
* @var string
*/
protected $password;
/**
* @ORM\Column(name="first_name", type="string", length=64)
*
* @access protected
* @var string
*/
protected $firstName;
/**
* @ORM\Column(name="last_name", type="string", length=64)
*
* @access protected
* @var string
*/
protected $lastName;
/**
* @ORM\Column(name="created_at", type="datetime")
*
* @access protected
* @var DateTime
*/
protected $createdAt;
/**
* @ORM\Column(name="last_login", type="datetime", nullable=true)
*
* @access protected
* @var DateTime
*/
protected $lastLogin;
/**
* @ORM\Column(name="confirmation_token", type="string", length=255, nullable=true)
*
* @access protected
* @var string
*/
protected $confirmationToken;
/**
* @ORM\Column(name="password_requested_at", type="datetime", nullable=true)
*
* @access protected
* @var DateTime
*/
protected $passwordRequestedAt;
/**
* @ORM\Column(type="boolean")
*
* @access protected
* @var boolean
*/
protected $enabled;
/**
* @ORM\Column(type="boolean")
*
* @access protected
* @var boolean
*/
protected $locked;
/**
* @ORM\Column(type="boolean")
*
* @access protected
* @var boolean
*/
protected $expired;
/**
* @ORM\Column(name="expires_at", type="datetime", nullable=true)
*
* @access protected
* @var DateTime
*/
protected $expiresAt;
/**
* @ORM\Column(name="credentials_expired", type="boolean")
*
* @access protected
* @var boolean
*/
protected $credentialsExpired;
/**
* @ORM\Column(name="credentials_expire_at", type="datetime", nullable=true)
*
* @access protected
* @var DateTime
*/
protected $credentialsExpireAt;
/**
* @ORM\Column(type="array")
*
* @access protected
* @var array
*/
protected $roles;
/**
* Constructor
*/
public function __construct()
{
$this->createdAt = new DateTime();
$this->enabled = true;
$this->locked = false;
$this->expired = false;
$this->credentialsExpired = false;
$this->roles = array();
}
/**
* Return the primary identifier.
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Return the username.
*
* @return string
*/
public function getUsername()
{
return $this->getEmail();
}
/**
* Return the email address.
*
* @return string
*/
public function getEmail()
{
return $this->email;
}
/**
* Set the email address.
*
* @param string $email
* @return User
*/
public function setEmail($email)
{
$this->email = $email;
return $this;
}
/**
* Return the canonical email address in search and sort queries.
*
* @return string
*/
public function getEmailCanonical()
{
return $this->email;
}
/**
* Set the canonical email address in search and sort queries.
*
* @param string $emailCanonical
* @return User
*/
public function setEmailCanonical($emailCanonical)
{
$this->emailCanonical = $emailCanonical;
return $this;
}
/**
* Returns the plain password.
*
* @return string
*/
public function getPlainPassword()
{
return $this->plainPassword;
}
/**
* Sets the plain password.
*
* @param string $plainPassword
* @return self
*/
public function setPlainPassword($plainPassword)
{
$this->plainPassword = $plainPassword;
return $this;
}
/**
* Returns the password.
*
* @return string
*/
public function getPassword()
{
return $this->password;
}
/**
* Sets the password.
*
* @param string $password
* @return self
*/
public function setPassword($password)
{
$this->password = $password;
return $this;
}
/**
* Erases the credentials.
*
* @return null
*/
public function eraseCredentials()
{
$this->plainPassword = null;
return $this;
}
/**
* Returns the salt.
*
* @return null
*/
public function getSalt()
{
return null;
}
/**
* Returns the first name.
*
* @return string
*/
public function getFirstName()
{
return $this->firstName;
}
/**
* Sets the first name.
*
* @param string $firstName
* @return self
*/
public function setFirstName($firstName)
{
$this->firstName = $firstName;
return $this;
}
/**
* Returns the last name.
*
* @return string
*/
public function getLastName()
{
return $this->lastName;
}
/**
* Sets the last name.
*
* @param string $lastName
* @return self
*/
public function setLastName($lastName)
{
$this->lastName = $lastName;
return $this;
}
/**
* Retruns created at time.
*
* @return DateTime
*/
public function getCreatedAt()
{
if (! $this->createdAt) {
$this->setCreatedAt(new DateTime);
}
return $this->createdAt;
}
/**
* Sets created at time.
*
* @param DateTime $createdAt
* @return self
*/
public function setCreatedAt(DateTime $createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* Returns the last login time.
*
* @return DateTime
*/
public function getLastLogin()
{
return $this->lastLogin;
}
/**
* Sets the last login time.
*
* @param DateTime $lastLogin
* @return self
*/
public function setLastLogin(DateTime $lastLogin)
{
$this->lastLogin = $lastLogin;
return $this;
}
/**
* Returns the confirmation token.
*
* @return string
*/
public function getConfirmationToken()
{
return $this->confirmationToken;
}
/**
* Sets the confirmation token.
*
* @param string $confirmationToken
* @return self
*/
public function setConfirmationToken($confirmationToken)
{
$this->confirmationToken = $confirmationToken;
return $this;
}
/**
* Return the password request at time.
*
* @return DateTime
*/
public function getPasswordRequestedAt()
{
return $this->passwordRequestedAt;
}
/**
* Sets the password requested at time.
*
* @param DateTime $passwordRequestedAt
* @return self
*/
public function setPasswordRequestedAt(DateTime $passwordRequestedAt)
{
$this->passwordRequestedAt = $passwordRequestedAt;
return $this;
}
/**
* Checks whether the user is enabled.
*
* @return boolean
*/
public function isEnabled()
{
return $this->enabled;
}
/**
* Sets the enabled status of the user.
*
* @param boolean $enabled
* @return self
*/
public function setEnabled($enabled)
{
$this->enabled = $enabled;
return $this;
}
/**
* Checks whether the user is locked.
*
* @return boolean
*/
public function isLocked()
{
return ! $this->isAccountNonLocked();
}
/**
* Checks whether the user is locked.
*
* @return boolean
*/
public function isAccountNonLocked()
{
return ! $this->locked;
}
/**
* Sets the locked status of the user.
*
* @param boolean $locked
* @return self
*/
public function setLocked($locked)
{
$this->locked = $locked;
return $this;
}
/**
* Checks whether the user is expired.
*
* @return boolean
*/
public function isExpired()
{
return ! $this->isAccountNonExpired();
}
/**
* Checks whether the user is expired.
*
* @return boolean
*/
public function isAccountNonExpired()
{
if (true === $this->expired) {
return false;
}
if (null !== $this->expiresAt && $this->expiresAt->getTimestamp() < time()) {
return false;
}
return true;
}
/**
* Sets the expired status of the user.
*
* @param boolean $expired
* @return self
*/
public function setAccountExpired($expired)
{
$this->expired = $expired;
return $this;
}
/**
* Returns the expired at time.
*
* @return DateTime
*/
public function getExpiredAt()
{
return $this->expiresAt;
}
/**
* Sets the expired at time.
*
* @param DateTime $expiresAt
* @return self
*/
public function setExpiredAt($expiresAt)
{
$this->expiresAt = $expiresAt;
return $this;
}
/**
* Check whether the user's credentials (password) has expired.
*
* @return boolean
*/
public function isCredentialsExpired()
{
return ! $this->isCredentialsNonExpired();
}
/**
* Check whether the user's credentials (password) has expired.
*
* @return boolean
*/
public function isCredentialsNonExpired()
{
if (true === $this->credentialsExpired) {
return false;
}
if (null !== $this->credentialsExpireAt && $this->credentialsExpireAt->getTimestamp() < time()) {
return false;
}
return true;
}
/**
* Set the user's credentials (password) expired status.
*
* @param boolean $credentialsExpired
* @return self
*/
public function setCredentialsExpired($credentialsExpired)
{
$this->credentialsExpired = $credentialsExpired;
}
/**
* Return the credentials expired at time.
*
* @return DateTime
*/
public function getCredentialsExpiredAt()
{
return $this->credentialsExpireAt;
}
/**
* Set the credentials expired at time.
*
* @param DateTime $credetialsExpiredAt
* @return User
*/
public function setCredentialsExpiredAt($credentialsExpiredAt)
{
$this->credentialsExpiredAt = $credentialsExpiredAt;
return $this;
}
/**
* Return list fo roles.
*
* @return array
*/
public function getRoles()
{
$roles = array_merge($this->roles, array('ROLE_USER'));
/*foreach ($this->getGroups() as $group)
{
$roles = array_merge($roles, $group->getRoles());
}*/
return array_unique($roles);
}
/**
* Compares this user to another to determine if they are the same.
*
* @todo: Maybe we should refresh user in listener, to prevent logout after making changes?
*
* @param UserInterface $user
* @return boolean True if equal, False otherwise.
*/
public function isEqualTo(SymfonyUserInterface $user)
{
return
md5($user->getUsername()) == md5($this->getUsername()) &&
md5(serialize($user->getRoles())) == md5(serialize($this->getRoles()));
}
/**
* @see \Serializable::serialize()
*/
public function serialize()
{
return serialize(array(
$this->id,
$this->email,
$this->emailCanonical,
$this->plainPassword,
$this->password,
$this->firstName,
$this->lastName,
$this->createdAt,
$this->lastLogin,
$this->confirmationToken,
$this->passwordRequestedAt,
$this->enabled,
$this->locked,
$this->expired,
$this->expiresAt,
$this->credentialsExpired,
$this->credentialsExpireAt,
$this->roles,
));
}
/**
* @see \Serializable::unserialize()
*/
public function unserialize($serialized)
{
//$data = unserialize($serialized);
// add a few extra elements in the array to ensure that we have enough keys when unserializing
// older data which does not include all properties.
//$data = array_merge($data, array_fill(0, 2, null));
list (
$this->id,
$this->email,
$this->emailCanonical,
$this->plainPassword,
$this->password,
$this->firstName,
$this->lastName,
$this->createdAt,
$this->lastLogin,
$this->confirmationToken,
$this->passwordRequestedAt,
$this->enabled,
$this->locked,
$this->expired,
$this->expiresAt,
$this->credentialsExpired,
$this->credentialsExpireAt,
$this->roles,
) = unserialize($serialized);
}
}
@edit 2: 認証の直後にイベントをキャッチしてそこからユーザーを取得し、getId() メソッドを呼び出すと、id 1 が返されます。したがって、認証プロセスに問題はないと思います...
自分の認証アダプターではなく、認証アダプターで UsernamePasswordToken を返すと、同じことが起こります。getId() を 0 として返します。