/** * Replicates the original method behaviour, but also adds the ability to find a user by its Social Network Link. * @param array $credentials * @return \Illuminate\Database\Eloquent\Model|null|static */ public function retrieveByCredentials(array $credentials) { if (isset($credentials['provider'])) { $network = SocialNetwork::find($credentials['provider']); if ($network) { /** @var SocialLink $profile */ $profile = $network->links()->where('username', $credentials['username'])->get(); if ($profile) { return $profile->user; } } return null; } else { return parent::retrieveByCredentials($credentials); } }
public function getCallback(string $provider) { try { $data = $this->driver($provider)->user(); //if there's already an user with this social account, let's log him in! /** @var SocialLink $link */ if ($link = SocialNetwork::find($provider)->links()->where('username', $data->getId())->with('user')->first()) { return $this->loginAfterSignUp($link->user, $provider); } //if there's already an user with this social email, let's merge accounts /** @var User $user */ if (($user = \Auth::user()) || $data->getEmail() && ($user = User::where('email', $data->getEmail())->first())) { $this->fillUser($user, $data->user, $data, $provider); if (\DB::transaction(function () use($user) { //tries to save the user data from fillUser + the main network. If it fails, throw up $user->throwOnValidation = true; $user->save(); $this->saveLinks($user, true); return true; })) { //if it works, let's go ahead, save other links (that might fail in case they're dups) and finish $this->saveLinks($user); return $this->loginAfterSignUp($user, $provider); } } $user = new User(); $this->fillUser($user, $data->user, $data, $provider); $user->username = $user->username ?? $data->getNickname() ?? strtok($user->email, '@'); $user->picture = $user->picture ?? $user->avatar; //for some odd reason, Laravel is unable to automatically serialize the user object(?), so we do it by hand session()->set('signup.user', serialize($user)); return view('auth.finishSignUp', compact('user', 'provider')); } catch (InvalidModelException $e) { return redirect()->action('AuthController@getSignUp')->with('social_error', true)->with('provider', $provider)->withErrors($e->getErrors()); } catch (\Exception $e) { \Log::error(class_basename($e) . ' during social callback (' . printr($_GET) . '): [' . $e->getCode() . '] ' . $e->getMessage()); $redirect = redirect()->action('AuthController@getSignUp')->with('social_error', true)->with('provider', $provider); if ($errors = request()->getSession()->get('errors')) { $redirect->withErrors($errors->getBag('default')); } return $redirect; } }
/** * Creates a {@link SocialLink} for the current user * @param string|int $username The username data to be stored * @param string $provider One recognizable provider name (from {@link SocialNetwork}) * @return SocialLink * @throws InvalidModelException in case there's an issue with SocialLink validation */ public function addLink($username, string $provider) { $link = new SocialLink(); try { $link->network()->associate(SocialNetwork::find($provider)); $link->user()->associate($this); $link->username = $username; $link->throwOnValidation = true; $link->save(); } catch (QueryException $e) { //integrity constraint violation: duplicate key && duplicate page == can be ignored if (!($e->getCode() == 23505 && stripos($e->getMessage(), 'unique_social_user'))) { throw $e; //not an "expected" error, so let's throw it up } } return $link; }