Laravel 5 Socialite - динамическое изменение пути перенаправления авторизации

Я пытаюсь включить Socialite в сайт и столкнулся с проблемой, которая должна быть довольно тривиальной - изменить место перенаправления пользователя после аутентификации поставщиком социальной сети.

У меня есть три действия, для которых я буду использовать Socialite:

  • Зарегистрируйтесь. Выполните аутентификацию у провайдера, а затем перейдите к форме регистрации. За них заполняются их имя и адрес электронной почты, требуются дополнительные поля.
  • Вход - типичный сценарий входа в систему, информация о поставщике проверяется по таблице «Пользователи», и они входят в систему, если есть совпадение.
  • Ссылка: у пользователя уже есть активная учетная запись, но он хотел бы привязать внешнюю учетную запись (Faceebook или Google). Это аутентифицирует пользователя и добавляет правильный идентификатор социальной сети в его строку в таблице Users. Проблема в том, что вы указываете перенаправление аутентификации в файле services.php, я не могу понять, как изменить, куда перенаправляется пользователь после успешной аутентификации у стороннего провайдера.

Вот что у меня есть на данный момент -

Маршрут: похоже, это работает до тех пор, пока социальный провайдер не перенаправляет, потому что driver=facebook&action=login (например) отсутствует. В идеале я хотел бы указать, куда перенаправляется пользователь при выполнении первоначального запроса аутентификации - это была только моя первая попытка выяснить это.

get('social-auth', function(AuthenticateUser $authenticateUser, Request $request) {
    $driver = $request->input('driver');
    $action = $request->input('action');

    return $authenticateUser->execute($request->has('code'), $driver, $action);
});

Класс AuthenticateUser - Надеюсь, здесь достаточно комментариев:

<?php namespace App;

use Illuminate\Database\Eloquent\ModelNotFoundException;
use Laravel\Socialite\Contracts\Factory as Socialite;
use Auth;
use Flash;

class AuthenticateUser
{
    /**
     * @var Socialite
     */
    private $socialite;
    /**
     * @var Auth
     */
    private $auth;

    public function __construct(Socialite $socialite, Auth $auth)
    {

        $this->socialite = $socialite;
        $this->auth = $auth;
    }

    /**
     * @param boolean $hasCode Whether or not we have been authenticated already
     * @param string $driver Driver to use, Facebook or Google
     * @param string $type Type of call - Login, Register, or Link
     * @return array|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
     */
    public function execute($hasCode, $driver, $type)
    {
        if (!$hasCode) {
            return $this->getAuthorizationFirst($driver);
        }

        // Get the User details from the Social Provider
        $socialUser = $this->socialite->driver($driver)->user();
        $socialUserArray = $socialUser->user;

        if ($driver == 'facebook') {
            // Get Facebook specific fields
            $first_name = $socialUserArray['first_name'];
            $last_name = $socialUserArray['last_name'];
        } else if ($driver == 'google') {
            // Get Google specific fields
            $first_name = $socialUserArray['name']['givenName'];
            $last_name = $socialUserArray['name']['familyName'];
        }
        $email = $socialUser->email;
        $id = $socialUser->id;

        // Perform an action - login, register, or link
        switch ($type) {
            case 'login':
                // Log the user in with the Facebook ID
                try {
                    if ($driver == 'facebook') {
                        $user = User::whereFacebookAuth($id)->firstOrFail();
                    } else {
                        $user = User::whereGoogleAuth($id);
                    }
                } catch (ModelNotFoundException $e) {
                    flash::error('Could not find a user associated with this ' . ucfirst($driver) . ' account.');
                    return redirect('auth/login');
                }
                Auth::login($user);
                return redirect('members');
                break;
            case 'register':
                // Register using social media account
                return redirect('register')
                    ->with('social_type', $driver)
                    ->with('social_id', $id)
                    ->with('email', $email)
                    ->with('first_name', $first_name)
                    ->with('last_name', $last_name);
                break;
            case 'link':
                // Associate this Social Media account with the current User
                $driver == 'facebook' ? Auth::user()->facebook_auth = $id : Auth::user()->google_auth = $id;
                Auth::user()->save();
                return ['status' => 'success'];
                break;
        }
    }

    /**
     * Authorize the user before proceeding
     * @param $driver
     * @return mixed
     */
    private function getAuthorizationFirst($driver)
    {
        return $this->socialite->with($driver)->redirect('hopefully-somewhere-else'); 
    // Anything inside redirect doesn't seem to do anything
    }
}

person NightMICU    schedule 18.03.2015    source источник
comment
Мы пошли в совершенно другом направлении: stackoverflow.com/a/42352903/186782   -  person zmonteca    schedule 20.02.2017


Ответы (2)


Я стараюсь включать поставщика в свои URL-адреса. Например:

Route::get('auth/{provider}', 'AuthController@redirectToProvider');
Route::get('auth/{provider}/callback', 'AuthController@handleProviderCallback');

Таким образом, я могу получить доступ к имени поставщика из запроса в действиях моего контроллера:

public function callback($provider)
{
    $user = $this->socialite->driver($provider)->getUser();

    try {
        // Try and find user by their social profile UID
        $appUser = SocialAccount::whereUid($user->getId())
            ->whereProvider($provider)
            ->firstOrFail();

        Auth::loginUsingId($appUser->user_id);
    } catch (ModelNotFoundException $e) {
        if (Auth::user()) {
            // Attach social profile to logged in user
        } else {
            // User is not logged in, and account does not exist
            // Prompt to register
        }
    }
}
person Martin Bean    schedule 18.03.2015
comment
Спасибо за ответ, но часть провайдера - не самая большая проблема, она обрабатывает несколько действий - вход в систему, регистрацию и связывание (как описано в вопросе). Единственное, о чем я могу думать, - это иметь драйвер для каждого в services.php с путем перенаправления для каждого (вход, регистрация, ссылка), но должен быть лучший способ - person NightMICU; 18.03.2015
comment
Обычно у вас будет один обратный вызов, который проверяет, использовалась ли сторонняя учетная запись для входа в систему, и если да, просто выполняет вход в систему соответствующего пользователя. Если нет, и пользователь вошел в систему, прикрепите учетную запись социальной сети к своему профилю. В противном случае предоставьте регистрационную форму (с данными, предварительно заполненными из социального профиля) и поля для ввода любой другой информации, необходимой для вашего веб-сайта. - person Martin Bean; 18.03.2015
comment
Это сайт с жесткими ограничениями, поэтому все новые участники должны быть одобрены до входа в систему (требование безопасности). Если пользователь нажимает «Зарегистрироваться с помощью« Social Provider », ему будет предложено авторизовать сайт, а затем он будет перенаправлен в регистрационную форму, где их данные будут предварительно заполнены. Если у них уже есть активная учетная запись, я хочу, чтобы они могли позже связать учетную запись в социальной сети. Третий сценарий - это просто вход в систему. Поэтому мне нужно иметь несколько путей перенаправления к моему приложению для обработки этих различных сценариев. - person NightMICU; 18.03.2015
comment
Кроме того, адрес электронной почты пользователя на моем сайте может не совпадать (и, вероятно, не будет) совпадать с адресом выбранного им социального провайдера, поэтому я использую его идентификатор пользователя, а не адрес электронной почты, указанный поставщиком. Вот почему мне нужна эта информация для регистрации и ссылки позже. - person NightMICU; 18.03.2015
comment
Да, вы бы сохранили UID профиля вместе с идентификатором пользователя вашего сайта. Поэтому, если я аутентифицируюсь с помощью Facebook, вы сохраните мой идентификатор профиля Facebook вместе с моим идентификатором пользователя. Таким образом, все последующие запросы аутентификации, которые вы будете знать, относятся к моей учетной записи. Вам придется использовать UID в любом случае, поскольку Twitter не раскрывает адреса электронной почты пользователей через их API. - person Martin Bean; 18.03.2015
comment
Хорошо, проблема заключается в перенаправлении на разные конечные точки в моем приложении для обработки трех разных задач - если бы я хотел только регистрировать пользователей, это было бы проще простого. Есть мысли о том, как я могу справиться с перенаправлением? Я работаю только с Facebook и Google, оба допускают несколько путей перенаправления. - person NightMICU; 18.03.2015
comment
Опять же, у вас будет один обратный вызов, который определяет, нужно ли входить в систему, регистрироваться или связывать учетную запись. Я обновил свой ответ, чтобы проиллюстрировать это. - person Martin Bean; 18.03.2015
comment
facepalm Почему я не подумал об этом? Спасибо брат :) - person NightMICU; 18.03.2015
comment
Ха-ха, не беспокойтесь. Рад, что помог. - person Martin Bean; 18.03.2015

Поздно присоединиться к вечеринке, но может помочь другим. Если вы хотите обрабатывать несколько перенаправлений, таких как вход, регистрация, привязка учетной записи социальной сети к профилю пользователя, это можно сделать, переопределив конфигурацию службы со стороны вашего контроллера.

config(['services.google.redirect' => <Your New URL here> ]);
Socialite::driver('google')->redirect();

Примечание: - Есть некоторые социальные платформы, которые строго требуют упоминания URL-адреса перенаправления в их консоль разработчика. Поэтому вам нужно указать здесь каждый URL-адрес перенаправления.

person Satyandra Shakya    schedule 29.06.2021