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

Problem with authorization through social network new user. Return 404

Open grozzzny opened this issue 4 years ago • 19 comments

https://github.com/2amigos/yii2-usuario/blob/8adbffeb3f2da4e2bd77be8d7e06a1629904734f/src/User/Controller/RegistrationController.php#L158

Pls, help me. The problem with authorization through social network new user. Return 404 /user/registration/connect?code=FMwHPLCI*****************DJC

    // Da\User\Controller\RegistrationController
    public function actionConnect($code)
    {
        /** @var SocialNetworkAccount $account */
        $account = $this->socialNetworkAccountQuery->whereCode($code)->one();
        if ($account === null || $account->getIsConnected()) {
            throw new NotFoundHttpException(); // !!!!!!!!!!  social_account not saved
        }
        ...
}
// Da\User\Service\SocialNetworkAuthenticateService
protected function createAccount()
    {
        $data = $this->client->getUserAttributes();

        /** @var SocialNetworkAccount $account */
        $account = $this->controller->make(
            SocialNetworkAccount::class,
            [],
            [
                'provider' => $this->client->getId(),
                'client_id' => $data['id'],
                'data' => json_encode($data),
                'username' => $this->client->getUserName(),
                'email' => $this->client->getEmail(),
            ]
        );
        // !!!!!!!!!!!!!!!!! User not found => social_account not save
        if (($user = $this->getUser($account)) instanceof User) {
            $account->user_id = $user->id;
            $account->save(false);
        }

        return $account;
    }

grozzzny avatar Jun 05 '20 10:06 grozzzny

I tried all events. The problem is solved only this way, otherwise redirecting to 404

Config. Event beforeAuthenticate handler

 'user' => [
            'class' => Da\User\Module::class,
            'controllerMap' => [
 'security' => [
                    'class' => 'Da\User\Controller\SecurityController',
                    'on beforeAuthenticate' => ['app\components\SocialNetworkHandler', 'beforeAuthenticate']
                ],
     ],
],

file components/SocialNetworkHandler.php

<?php


namespace app\components;


use Da\User\Event\SocialNetworkAuthEvent;
use Da\User\Factory\MailFactory;
use Da\User\Model\User;
use Da\User\Service\UserCreateService;
use Yii;
use yii\base\BaseObject;

class SocialNetworkHandler extends BaseObject
{
    /**
     * @param SocialNetworkAuthEvent $event
     */
    public static function beforeAuthenticate($event)
    {
        /** @var User $model */
        $user = Yii::$container->get(User::class);

        if($user::find()->where(['email' => $event->client->email])->exists()) return;

        $user = new $user([
            'scenario' => 'create',
            'email' => $event->client->email,
            'username' => $event->client->username,
            'password' => null
        ]);

        /** @var MailFactory $mailFactory */
        $mailFactory = Yii::$container->get(MailFactory::class);
        $mailService = $mailFactory::makeWelcomeMailerService($user);

        /** @var UserCreateService $userCreateService */
        $userCreateService = Yii::$container->get(UserCreateService::class, [$user, $mailService]);
        $userCreateService->run();

        $event->account->user_id = $user->id;
        $event->account->save();

        Yii::$app->user->login($user);
    }
}

grozzzny avatar Jun 05 '20 11:06 grozzzny

I also noticed this bug. i fixed it moving save(false) outside the IF statement. ugly fix though.

BEFORE

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

AFTER

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

mkodummy avatar Jun 18 '20 11:06 mkodummy

@grozzzny from your code I made an even simpler fix. Thanks for the insight on the beforeAuthenticate hook. My final SocialNetworkHandler.php file is only the code below. Rest is exactly the same as you pointed out.

class SocialNetworkHandler extends BaseObject
{
    /**
     * @param SocialNetworkAuthEvent $event
     */
    public static function beforeAuthenticate($event)
    {
        return $event->account->save(false);
    }
}

Saving the social account like above already unlocks the entire user registration/welcome email etc. stuff existing, in my project the code below is redundant ( of course, unless you are customizing it)

 $user = new $user([
            'scenario' => 'create',
            'email' => $event->client->email,
            'username' => $event->client->username,
            'password' => null
        ]);

        /** @var MailFactory $mailFactory */
        $mailFactory = Yii::$container->get(MailFactory::class);
        $mailService = $mailFactory::makeWelcomeMailerService($user);

        /** @var UserCreateService $userCreateService */
        $userCreateService = Yii::$container->get(UserCreateService::class, [$user, $mailService]);
        $userCreateService->run();

```

mkodummy avatar Jun 18 '20 12:06 mkodummy

Thanks, @mkodummy. I will test later.

grozzzny avatar Jun 18 '20 12:06 grozzzny

@mkodummy and @grozzzny Thanks, the last change works!

But I get this warning when login with github:

Please use the Authorization HTTP header instead as using the access_token query parameter is deprecated.

Depending on your API usage, we'll be sending you this email reminder on a monthly basis.

Visit https://developer.github.com/changes/2020-02-10-deprecating-auth-through-query-param for more information about suggested workarounds and removal dates.

whisere avatar Jun 23 '20 01:06 whisere

Thanks so much @mkodummy and @grozzzny, it worked for me. I searched for a few hours to find this topic.

vinhhung1108 avatar Aug 18 '20 09:08 vinhhung1108

this happened to me also ... and I reached this page ... why is not fixed in the official repo ?

dantart avatar Nov 11 '20 23:11 dantart

For PHP 7.4+

    'user' => [
        'class' => Da\User\Module::class,
        'controllerMap' => [
            'security' => [
                'class' => Da\User\Controller\SecurityController::class,
                'on beforeAuthenticate' =>
                    static fn (Da\User\Event\SocialNetworkAuthEvent $event) => $event->account->save(false),
            ],
        ],
        // ...
    ],

mj4444ru avatar Apr 19 '21 13:04 mj4444ru

This solution worked like a charm!

For PHP 7.4+

    'user' => [
        'class' => Da\User\Module::class,
        'controllerMap' => [
            'security' => [
                'class' => Da\User\Controller\SecurityController::class,
                'on beforeAuthenticate' =>
                    static fn (Da\User\Event\SocialNetworkAuthEvent $event) => $event->account->save(false),
            ],
        ],
        // ...
    ],

Jonyx4 avatar Jun 16 '21 00:06 Jonyx4

For PHP 7.4+

    'user' => [
        'class' => Da\User\Module::class,
        'controllerMap' => [
            'security' => [
                'class' => Da\User\Controller\SecurityController::class,
                'on beforeAuthenticate' =>
                    static fn (Da\User\Event\SocialNetworkAuthEvent $event) => $event->account->save(false),
            ],
        ],
        // ...
    ],

@jonyx4 @mj4444ru

I added this in my main.php anything else to add? doesm't seem to work for me. new accounts not getting registered with social networks.

srakl avatar Jul 11 '21 09:07 srakl

@grozzzny i tried your steps, after i login with google, it redirects me to user/registration/connect&code=adssad how do i get it to skip that? and get fill in the firtsname lastname email etc from google

srakl avatar Jul 12 '21 17:07 srakl

For PHP 7.4+

    'user' => [
        'class' => Da\User\Module::class,
        'controllerMap' => [
            'security' => [
                'class' => Da\User\Controller\SecurityController::class,
                'on beforeAuthenticate' =>
                    static fn (Da\User\Event\SocialNetworkAuthEvent $event) => $event->account->save(false),
            ],
        ],
        // ...
    ],

@Jonyx4 @mj4444ru

I added this in my main.php anything else to add? doesm't seem to work for me. new accounts not getting registered with social networks.

I don't know if this is related to your issue, but I also had to apply the fix described in this issue https://github.com/2amigos/yii2-usuario/issues/397

Jonyx4 avatar Jul 12 '21 18:07 Jonyx4

@Jonyx4 unfortunately adding the return $account; still redirects the user to user/registration/connect&code=adssad to confirm registration. it should auto fill in firstname lastname etc into db :(

srakl avatar Jul 12 '21 18:07 srakl

This works for me:

 'security' => [
                    'class' => 'Da\User\Controller\SecurityController',
                    'on beforeAuthenticate' => ['frontend\controllers\SocialNetworkHandler', 'beforeAuthenticate']
                ],

frontend\controllers\SocialNetworkHandler:

namespace frontend\controllers;

use Da\User\Event\SocialNetworkAuthEvent;
use Da\User\Factory\MailFactory;
use Da\User\Model\User;
use Da\User\Service\UserCreateService;
use Yii;
use yii\base\BaseObject;

class SocialNetworkHandler extends BaseObject
{
    /**
     * @param SocialNetworkAuthEvent $event
     */
    public static function beforeAuthenticate($event)
    {
        return $event->account->save(false);
    }
}

whisere avatar Jul 13 '21 00:07 whisere

@whisere does yours redirect newly registered users to the user/registration/connect page to input their email etc after they click on the social connect button? how do i bypass that step?

srakl avatar Jul 13 '21 06:07 srakl

It is normal that's just a step for user to confirm/edit their user name and email in the system (they may not want to use the same user name and email used in the social media account), it should automatically fill in the email address from social account.

whisere avatar Jul 13 '21 07:07 whisere

@whisere cool, thanks. if i was to skip that step, and auto fill firstname and last name from social account, know which file i can edit or extend by any chance?

srakl avatar Jul 13 '21 07:07 srakl

There may not be first and last name from social account, you can see: https://github.com/2amigos/yii2-usuario/tree/master/src/User/AuthClient (better to fork your own repo/copy if to make change to code)

overwriting controllers in the documentation: https://yii2-usuario.readthedocs.io/en/latest/enhancing-and-overriding/overriding-controllers/# and social events and other events under the events menu: https://yii2-usuario.readthedocs.io/en/latest/events/social-network-connect-events/

whisere avatar Jul 14 '21 00:07 whisere

@whisere thanks. for the most part i got it working. It just doesn't seem to save the firstname and lastname in the user table. any idea what im missing here? here are the changes i made to the controller. https://github.com/2amigos/yii2-usuario/issues/418

srakl avatar Jul 14 '21 07:07 srakl