If you want to use your custom User class (eg App\Entity\User) the solution is to make your own User Provider. If you want users to be able to authenticate with a traditional login form and also with HWIOAuthBundle then you could start to make your own User provider as described here. Of course you have to add some code inside the two methods before it works (see example below) and do not forget to setup the providers section in security.yaml like so:
providers:
# used to reload user from session & other features (e.g. switch_user)
app_user_provider:
id: App\Security\UserProvider
Then if you can authenticate with your traditional login form through your newly created User Provider and it all works well you can start to integrate HWIOAuthBundle. Start to direct the oauth_user_provider setting to your own User Provider class. Your main firewall could look like this:
firewalls:
main:
anonymous: true
oauth:
resource_owners:
facebook: "/login/check-facebook"
oauth_user_provider:
service: App\Security\UserProvider # HERE YOU GO!
login_path: /login
use_forward: false
failure_path: /login
form_login:
login_path: /login
guard:
authenticators:
- App\Security\LoginFormAuthenticator
logout:
path: app_logout
By the way your App\Security\UserProvider class should be auto-wired in the service container. If not you have to add the service manually to your service.yaml.
If you now try to login with a resource owner (eg Facebook or Google) from HWIOAuthBundle then you will get an error because your User Provider class must implement HWI's OAuthAwareUserProviderInterface. A quick look into that interface source file will learn that you have to add one method to your User Provider:
loadUserByOAuthUserResponse(UserResponseInterface $response). So let your User Provider class implement HWI OAuthAwareUserProviderInterface and add the method to the class. It is pretty straightforward.
Here comes the full User Provider that i wrote for this test case:
<?php
namespace App\Security;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Doctrine\ORM\EntityManagerInterface;
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthAwareUserProviderInterface;
use App\Entity\User;
class UserProvider implements UserProviderInterface, OAuthAwareUserProviderInterface
{
private $em;
private $property = 'email';
public function __construct(EntityManagerInterface $em) {
$this->em = $em;
}
/**
* @return UserInterface
*/
public function loadUserByUsername($username)
{
$repository = $this->em->getRepository(User::class);
if (null !== $this->property) {
$user = $repository->findOneBy([$this->property => $username]);
} else {
if (!$repository instanceof UserLoaderInterface) {
throw new \InvalidArgumentException(sprintf('You must either make the "%s" entity Doctrine Repository ("%s") implement "Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface" or set the "property" option in the corresponding entity provider configuration.', $this->classOrAlias, \get_class($repository)));
}
$user = $repository->loadUserByUsername($username);
}
if (null === $user) {
throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
}
return $user;
}
/**
* @return UserInterface
*/
public function refreshUser(UserInterface $user)
{
if (!$user instanceof User) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', User::class));
}
$repository = $this->em->getRepository(User::class);
if ($repository instanceof UserProviderInterface) {
$refreshedUser = $repository->refreshUser($user);
} else {
$refreshedUser = $repository->find($user->getId());
if (null === $refreshedUser) {
throw new UsernameNotFoundException(sprintf('User with id %s not found', json_encode($user->getId())));
}
}
return $refreshedUser;
}
/**
* @return UserInterface
*/
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
return $this->loadUserByUsername($response->getEmail());
}
/**
* Tells Symfony to use this provider for this User class.
*/
public function supportsClass($class)
{
return User::class === $class;
}
}
This User Provider is still not ready. For example it will throw an exception if a unknown facebook/google/... user tries to login. You have to extend this example to your needs and thoroughly test it!