Symfony2 User must return UserInterface object on login
I am actually trying to create a login form that matches my database.
The form works well, but I have a problem with UserRepository
. Symfony tells me the following error:
The user provider must return a UserInterface object.
exception 'Symfony\Component\Security\Core\Exception\AuthenticationServiceException' with message 'The user provider must return a UserInterface object.' in C:\wamp\www\php\Promocast\Symfony\vendor\symfony\src\Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider.php:101
But as you can see below, my custom entity is implemented UserInterface
, so I don't really understand what this error is.
My custom object:
<?php
namespace Promocast\UtilisateurBundle\Entity;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\ORM\Mapping as ORM;
/**
* Promocast\UtilisateurBundle\Entity\ImUser
*
* @ORM\Entity(repositoryClass="Promocast\UtilisateurBundle\Entity\ImUserRepository")
*/
class ImUser implements UserInterface
{
/**
* Here all my var and getter/setter
* ...
*/
/**
* Fonctions UserInterface
*
*/
public function eraseCredentials()
{
}
public function getRoles()
{
return $this->idrole;
}
public function equals(UserInterface $user)
{
return $user->getUsername() === $this->login;
}
public function getUsername()
{
return $this->login;
}
public function getSalt()
{
return '';
}
}
My custom repository:
<?php
namespace Promocast\UtilisateurBundle\Entity;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NoResultException;
class ImUserRepository extends EntityRepository implements UserProviderInterface
{
public function loadUserByUsername($login)
{
$user = $this->findBy(array("login" => $login));
if (!$user) {
throw new UsernameNotFoundException(sprintf('No user with name "%s" was found.', $login));
}
return $user;
}
public function refreshUser(UserInterface $user)
{
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return $class === 'Promocast\UtilisateurBundle\Entity\ImUser';
}
}
And my security.yml:
security:
encoders:
Promocast\UtilisateurBundle\Entity\ImUser: plaintext
#Promocast\UtilisateurBundle\Security\Provider\LoginWebService: plaintext
role_hierarchy:
ROLE_USER_SUP: ROLE_USER
ROLE_ADMIN: ROLE_USER_SUP
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_USER_SUP, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
providers:
main:
entity: { class: PromocastUtilisateurBundle:ImUser }
#entity: { class: Promocast\UtilisateurBundle\Entity\ImUser, property: login }
#id: webservice_user_provider
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/(login$|register|resetting)
anonymous: true
main:
pattern: ^/
form_login:
login_path: /login
check_path: /login_check
username_parameter: _login
password_parameter: _password
remember_me:
key: %secret%
anonymous: true
provider: main
logout: true
logout:
path: /logout
target: /
access_control:
#- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
#- { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
#- { path: /.*, role: ROLE_USER }
#- { path: /login, role: IS_AUTHENTICATED_ANONYMOUSLY }
Thank you so much!
source to share
It looks like your problem is here:
public function loadUserByUsername($login)
{
$user = $this->findBy(array("login" => $login));
if (!$user) {
throw new UsernameNotFoundException(sprintf('No user with name "%s" was found.', $login));
}
return $user;
}
$this->findBy()
is probably returning a cursor / result set, not a single row as you intended (even if the result set only contains one row).
Try using $this->findOneBy()
this instead.
Based on your code, it looks like you are following the cookbook's guide on How to Load Security Users from a Database (Entity Provider) - but if you don't, it's a useful resource in this case.
source to share
Caveat: I am far from being an S2 security expert. I just post what works for me.
Your config file doesn't say anything about the system using ImUserRepository as service provider. So the system basically tries to use the default provider. Moreover, using a repository is problematic at best. Doctrine repos can only come from Doctrine entity managers, so you are asking the system to say that my custom class is a doctrine object, so I have to use a repository, and I assume I will be using that entity manager. Will not happen.
Make your user provider a service, and then inject the entity manager into it.
security:
providers:
my_provider:
id: zayso_core.user.provider
<service id="zayso_core.user.provider" class="Zayso\CoreBundle\Component\User\UserProvider" public="true">
<argument type="service" id="doctrine.orm.accounts_entity_manager" />
<argument type="string">%zayso_core.user.class%</argument>
</service>
You probably also want to encode your passwords in the end like this:
security:
encoders:
Zayso\AreaBundle\Component\User\User:
id: zayso_core.user.encoder
<service id="zayso_core.user.encoder" class="Zayso\CoreBundle\Component\User\Encoder" public="true">
</service>
And that should force you.
source to share