yii2-usuario icon indicating copy to clipboard operation
yii2-usuario copied to clipboard

Social Network Authenticate Service no longer creates a new user

Open IvandaNothabeer opened this issue 5 years ago • 6 comments

The fix for #309 removed the feature that creates a New User from Social Network Logon if the user does not already exist.

Following Code was changed

https://github.com/2amigos/yii2-usuario/commit/dd407f50b482b472f290fdff741b85e8b52bacce#diff-527c5ba7064e8097f56bd9de2dac5f59

Social Network login already provides a validated email address and user name, there should be no need to complete the manual registration and verification process.

IvandaNothabeer avatar Oct 24 '19 04:10 IvandaNothabeer

Fixed this by adding code for event:

Event::on(
    SecurityController::class, SocialNetworkAuthEvent::EVENT_BEFORE_AUTHENTICATE, function (SocialNetworkAuthEvent $event) {
        $client = $event->getClient();
        $account = $event->getAccount();
        if ($account->user === null || !$account->user instanceof User) {
            /** @var User $user */
            $user = $event->sender->make(
                User::class,
                [],
                [
                    'scenario' => 'connect',
                    'username' => $account->username,
                    'email' => $account->email,
                ]
            );

            if (!$user->validate(['email'])) {
                $user->email = null;
            }

            if (!$user->validate(['username'])) {
                $user->username = null;
            }

            $mailService = MailFactory::makeWelcomeMailerService($user);

            if ($event->sender->make(UserCreateService::class, [$user, $mailService])->run()) {
                $account->user_id = $user->id;
                $account->save(false);
            }
        }
});

drSun avatar Jan 18 '20 11:01 drSun

I confirm. Registration through social networks does not work.

ivan-cc avatar Feb 26 '20 17:02 ivan-cc

I'm undecided if adding a configuration parameter which will optionally restore the old behaviour or just add @drSun solution to docs. @tonydspaniard what are the motivations of your change?

maxxer avatar Mar 15 '20 07:03 maxxer

+1. Need sign-up by social network functionality

I suggest to add parameter at class Module extends BaseModule something like

public $allowSignUpBySocialNetwork = true;

you can pass it when make the service:

class SocialNetworkAuthenticateService implements ServiceInterface
{
	protected $controller;
	protected $authAction;
	protected $client;
	protected $socialNetworkAccountQuery;
	protected $userQuery;
	protected $allowSignUpBySocialNetwork;

	public function __construct(
		SecurityController $controller,
		AuthAction $authAction,
		AuthClientInterface $client,
		SocialNetworkAccountQuery $socialNetworkAccountQuery,
		UserQuery $userQuery,
		$allowSignUpBySocialNetwork = true
	) {
		$this->controller = $controller;
		$this->authAction = $authAction;
		$this->client = $client;
		$this->socialNetworkAccountQuery = $socialNetworkAccountQuery;
		$this->userQuery = $userQuery;
		$this->allowSignUpBySocialNetwork = $allowSignUpBySocialNetwork;
	}

and at:

protected function createAccount()
{
   $data = $this->client->getUserAttributes();
   ...

   if (($user = $this->getUser($account)) instanceof User) {
		$account->user_id = $user->id;
		$account->save(false);
	} elseif ($this->allowSignUpBySocialNetwork) {
		$account->save(false);
	}
	
   return $account;
}

d3artagnan avatar May 15 '20 07:05 d3artagnan

The previous suggestion will add flexibility if we want or not, to only allowed a user to connect to social network after form registration.

On the other hand, why we don't keep the social network account, even if the user will not connect to it. It can be used for future connection anyway.

So can we save the social account anyhow?

class SocialNetworkAuthenticateService implements ServiceInterface
	...
	
    protected function createAccount()
    {
        $data = $this->client->getUserAttributes();

        ...

        if (($user = $this->getUser($account)) instanceof User) {
            $account->user_id = $user->id;
        }

        $account->save(false);

        return $account;
    }

d3artagnan avatar May 15 '20 07:05 d3artagnan

Fixed this by adding code for event:

Event::on(
    SecurityController::class, SocialNetworkAuthEvent::EVENT_BEFORE_AUTHENTICATE, function (SocialNetworkAuthEvent $event) {
        $client = $event->getClient();
        $account = $event->getAccount();
        if ($account->user === null || !$account->user instanceof User) {
            /** @var User $user */
            $user = $event->sender->make(
                User::class,
                [],
                [
                    'scenario' => 'connect',
                    'username' => $account->username,
                    'email' => $account->email,
                ]
            );

            if (!$user->validate(['email'])) {
                $user->email = null;
            }

            if (!$user->validate(['username'])) {
                $user->username = null;
            }

            $mailService = MailFactory::makeWelcomeMailerService($user);

            if ($event->sender->make(UserCreateService::class, [$user, $mailService])->run()) {
                $account->user_id = $user->id;
                $account->save(false);
            }
        }
});

@drSun where did u add this?

srakl avatar Jul 11 '21 11:07 srakl