Search code examples
phpsymfonyoauthhwioauthbundle

OAuth HwioBundle, different socialNetWork


I work to project in Symfony which have registration HWIOBundle for different social network. If user enters for example LinkedIn and some time for GitHub I has two user in database. Who knows how to do was one?


Solution

  • If user's email is similar in both social accounts, you can use email field to identify user. You should create user provider class. If user with provided social token won't be found in database, user provider will try to find user by email and add new social token for specified social network to existing user entity.

    Code example.

    services.xml

    <service id="app.my_user_provider" class="AppBundle\Security\FOSUBUserProvider">
        <argument type="service" id="user_manager"/>
        <argument type="collection">
          <argument key="facebook">%facebook_id%</argument>
          <argument key="google">%google_id%</argument>
        </argument>
        <argument type="service" id="event_dispatcher"/>
    </service>
    

    security.yml, firewall section

        oauth:
            resource_owners:
                facebook: "/login/check-facebook"
                google: "/login/check-google"
            login_path: /login
            failure_path: /login
    
            oauth_user_provider:
                service: app.my_user_provider
    

    src/AppBundle/Security/FOSUBUserProvider.php

    <?php
    
    namespace AppBundle\Security;
    
    use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
    use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider as BaseClass;
    use Symfony\Component\Security\Core\User\UserInterface;
    
    class FOSUBUserProvider extends BaseClass
    {
        /**
         * {@inheritDoc}
         */
        public function connect(UserInterface $user, UserResponseInterface $response)
        {
            $username = $response->getUsername();
    
            $service = $response->getResourceOwner()->getName();
            $setter = 'set' . ucfirst($service);
            $setterId = $setter . 'Id';
            $setterToken = $setter . 'AccessToken';
    
            //disconnect previously connected user
            if (null !== $previousUser = $this->userManager->findUserBy(array($this->getProperty($response) => $username))) {
                $previousUser->$setterId(null);
                $previousUser->$setterToken(null);
                $this->userManager->updateUser($previousUser);
            }
    
            //connect current user
            $user->$setterId($username);
            $user->$setterToken($response->getAccessToken());
    
            $this->userManager->updateUser($user);
        }
    
        /**
         * {@inheritdoc}
         */
        public function loadUserByOAuthUserResponse(UserResponseInterface $response)
        {
            $username = $response->getUsername();
            $email = $response->getEmail();
    
            $user = $this->userManager->findUserBy(array($this->getProperty($response) => $username));
            if (null === $user) {
                $user = $this->userManager->findUserByEmail($email);
    
                $service = $response->getResourceOwner()->getName();
                $setter = 'set' . ucfirst($service);
                $setterId = $setter . 'Id';
                $setterToken = $setter . 'AccessToken';
    
                if (null === $user) {
                    $user = $this->userManager->createUser();
                    $user->$setterId($username);
                    $user->$setterToken($response->getAccessToken());
    
                    $user->setUsername($username);
                    $user->setEmail($email);
                    $user->setPassword($username);
                    $user->setEnabled(true);
                    $this->userManager->updateUser($user);
    
                    return $user;
                } else {
                    $user->$setterId($username);
                    $user->$setterToken($response->getAccessToken());
    
                    $this->userManager->updateUser($user);
    
                    return $user;
                }
            }
    
            //if user exists - go with the HWIOAuth way
            $user = parent::loadUserByOAuthUserResponse($response);
    
            $serviceName = $response->getResourceOwner()->getName();
            $setter = 'set' . ucfirst($serviceName) . 'AccessToken';
    
            //update access token
            $user->$setter($response->getAccessToken());
    
            return $user;
        }
    }