2amigos / yii2-usuario

Highly customizable and extensible user management, authentication, and authorization Yii2 extension
https://github.com/2amigos/yii2-usuario
Other
292 stars 141 forks source link

Social Network Authenticate Service no longer creates a new user #359

Open IvandaNothabeer opened 4 years ago

IvandaNothabeer commented 4 years ago

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.

drSun commented 4 years ago

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);
            }
        }
});
ivan-cc commented 4 years ago

I confirm. Registration through social networks does not work.

maxxer commented 4 years ago

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?

d3artagnan commented 4 years ago

+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 commented 4 years ago

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;
    }
srakl commented 3 years ago

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?