fixing up the authenticator to allow identiy chaining
This commit is contained in:
@@ -1,77 +1,92 @@
|
||||
<?php namespace AdamWathan\EloquentOAuth;
|
||||
|
||||
use SocialNorm\User;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use SocialNorm\ProviderUser;
|
||||
|
||||
class Authenticator
|
||||
{
|
||||
protected $auth;
|
||||
/** @var \Illuminate\Auth\SessionGuard */
|
||||
protected $guard;
|
||||
/** @var UserStore */
|
||||
protected $users;
|
||||
/** @var IdentityStore */
|
||||
protected $identities;
|
||||
|
||||
public function __construct($auth, $users, $identities)
|
||||
public function __construct(\Illuminate\Auth\SessionGuard $auth, UserStore $users, IdentityStore $identities)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
$this->guard = $auth;
|
||||
$this->users = $users;
|
||||
$this->identities = $identities;
|
||||
}
|
||||
|
||||
public function login($providerAlias, $userDetails, $callback = null)
|
||||
public function login($providerAlias, ProviderUser $userDetails, $callback = null)
|
||||
{
|
||||
/** @var Model|Authenticatable $user */
|
||||
$user = $this->getUser($providerAlias, $userDetails);
|
||||
$user = $this->runCallback($callback, $user, $userDetails);
|
||||
$this->updateUser($user, $providerAlias, $userDetails);
|
||||
$this->auth->login($user);
|
||||
$this->guard->login($user);
|
||||
}
|
||||
|
||||
protected function getUser($providerAlias, \SocialNorm\User $details)
|
||||
protected function getUser($providerAlias, ProviderUser $details) // returns User
|
||||
{
|
||||
if ($this->identities->userExists($providerAlias, $details)) {
|
||||
if ($this->identities->userExists($providerAlias, $details, false)) {
|
||||
return $this->getExistingUser($providerAlias, $details);
|
||||
}
|
||||
|
||||
/** @var \App\Models\User $newuser */
|
||||
$newuser = $this->users->create();
|
||||
$newuser->name = $details->nickname ?: ($details->full_name ?: $details->email);
|
||||
$newuser->email = $details->email;
|
||||
return $newuser;
|
||||
// this is potentially unsafe - allows user to attach a social identity to an
|
||||
// existing account just my matching the e-mail.
|
||||
|
||||
// we have to assume the providers are trustworthy.
|
||||
if ($details->email && $this->identities->userExists($providerAlias, $details, true)) {
|
||||
return $this->users->findByEmail($details->email);
|
||||
}
|
||||
|
||||
return $this->users->create();
|
||||
}
|
||||
|
||||
protected function runCallback($callback, $user, $userDetails)
|
||||
protected function runCallback($callback, Model $user, ProviderUser $userDetails)
|
||||
{
|
||||
$callback = $callback ?: function () {};
|
||||
$callbackUser = $callback($user, $userDetails);
|
||||
return $callbackUser ?: $user;
|
||||
}
|
||||
|
||||
protected function updateUser($user, $providerAlias, $details)
|
||||
protected function updateUser(Model $user, $providerAlias, ProviderUser $details)
|
||||
{
|
||||
$this->users->store($user);
|
||||
$this->storeProviderIdentity($user, $providerAlias, $details);
|
||||
}
|
||||
|
||||
protected function getExistingUser($providerAlias, $details)
|
||||
protected function getExistingUser($providerAlias, ProviderUser $details)
|
||||
{
|
||||
$identity = $this->identities->getByProvider($providerAlias, $details);
|
||||
return $this->users->findByIdentity($identity);
|
||||
}
|
||||
|
||||
protected function storeProviderIdentity($user, $providerAlias, $details)
|
||||
protected function storeProviderIdentity(Model $user, string $providerAlias, ProviderUser $details)
|
||||
{
|
||||
if ($this->identities->userExists($providerAlias, $details)) {
|
||||
if ($this->identities->userExists($providerAlias, $details, false)) {
|
||||
$this->updateProviderIdentity($providerAlias, $details);
|
||||
} else {
|
||||
$this->addProviderIdentity($user, $providerAlias, $details);
|
||||
}
|
||||
}
|
||||
|
||||
protected function updateProviderIdentity($providerAlias, $details)
|
||||
protected function updateProviderIdentity(string $providerAlias, ProviderUser $details)
|
||||
{
|
||||
$identity = $this->identities->getByProvider($providerAlias, $details);
|
||||
$identity->access_token = $details->access_token;
|
||||
$this->identities->store($identity);
|
||||
}
|
||||
|
||||
protected function addProviderIdentity($user, $providerAlias, $details)
|
||||
/**
|
||||
* @param Model $user
|
||||
* @param $providerAlias
|
||||
* @param $details
|
||||
*/
|
||||
protected function addProviderIdentity(Model $user, string $providerAlias, ProviderUser $details)
|
||||
{
|
||||
$identity = new OAuthIdentity;
|
||||
$identity->user_id = $user->getKey();
|
||||
|
||||
@@ -1,28 +1,58 @@
|
||||
<?php namespace AdamWathan\EloquentOAuth;
|
||||
<?php
|
||||
namespace AdamWathan\EloquentOAuth;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use SocialNorm\ProviderUser;
|
||||
|
||||
class EloquentIdentityStore implements IdentityStore
|
||||
{
|
||||
public function getByProvider($provider, $providerUser)
|
||||
public function getByProvider(string $provider, ProviderUser $providerUser)
|
||||
{
|
||||
return OAuthIdentity::where('provider', $provider)
|
||||
->where('provider_user_id', $providerUser->id)
|
||||
->first();
|
||||
}
|
||||
|
||||
public function flush($user, $provider)
|
||||
/**
|
||||
* Try to retrieve user by their e-mail
|
||||
* (!!! this is coupled to the application code !!!)
|
||||
*
|
||||
* @param ProviderUser $providerUser
|
||||
* @return User|Model|null|object
|
||||
*/
|
||||
public function getByEmail(ProviderUser $providerUser)
|
||||
{
|
||||
$first = User::where('email', $providerUser->email)->first();
|
||||
|
||||
if($first->email) return $first;
|
||||
return null;
|
||||
}
|
||||
|
||||
public function flush(Model $user, string $provider)
|
||||
{
|
||||
OAuthIdentity::where('user_id', $user->getKey())
|
||||
->where('provider', $provider)
|
||||
->delete();
|
||||
}
|
||||
|
||||
public function store($identity)
|
||||
public function store(OAuthIdentity $identity)
|
||||
{
|
||||
$identity->save();
|
||||
}
|
||||
|
||||
public function userExists($provider, $providerUser)
|
||||
public function userExists(string $provider, ProviderUser $providerUser, bool $allowByEmail)
|
||||
{
|
||||
return (bool) $this->getByProvider($provider, $providerUser);
|
||||
$byProvider = (bool) $this->getByProvider($provider, $providerUser);
|
||||
if ($byProvider) return true;
|
||||
|
||||
if (!$allowByEmail) return false;
|
||||
|
||||
if ($providerUser->email) {
|
||||
$byEmail = $this->getByEmail($providerUser);
|
||||
if ($byEmail) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
<?php namespace AdamWathan\EloquentOAuth;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use SocialNorm\ProviderUser;
|
||||
|
||||
interface IdentityStore
|
||||
{
|
||||
public function getByProvider($provider, $providerUser);
|
||||
public function flush($user, $provider);
|
||||
public function store($identity);
|
||||
public function userExists($provider, $providerUser);
|
||||
public function getByProvider(string $provider, ProviderUser $providerUser);
|
||||
public function flush(Model $user, string $provider);
|
||||
public function getByEmail(ProviderUser $providerUser);
|
||||
public function store(OAuthIdentity $identity);
|
||||
public function userExists(string $provider, ProviderUser $providerUser, bool $allowByEmail);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?php namespace AdamWathan\EloquentOAuth;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model as Eloquent;
|
||||
use Config;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property $id
|
||||
@@ -10,14 +9,14 @@ use Config;
|
||||
* @property $provider_user_id
|
||||
* @property $access_token
|
||||
*/
|
||||
class OAuthIdentity extends Eloquent
|
||||
class OAuthIdentity extends Model
|
||||
{
|
||||
protected static $configuredTable = 'oauth_identities';
|
||||
|
||||
// public static function configureTable($table)
|
||||
// {
|
||||
// static::$configuredTable = $table;
|
||||
// }
|
||||
public static function configureTable($table)
|
||||
{
|
||||
static::$configuredTable = $table;
|
||||
}
|
||||
|
||||
public function getTable()
|
||||
{
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?php namespace AdamWathan\EloquentOAuth;
|
||||
|
||||
use SocialNorm\Provider;
|
||||
use SocialNorm\SocialNorm;
|
||||
|
||||
class OAuthManager
|
||||
{
|
||||
/** @var string */
|
||||
/** @var \Illuminate\Routing\Redirector */
|
||||
protected $redirect;
|
||||
|
||||
/** @var Authenticator */
|
||||
@@ -13,25 +14,32 @@ class OAuthManager
|
||||
/** @var SocialNorm */
|
||||
protected $socialnorm;
|
||||
|
||||
public function __construct($redirect, $authenticator, $socialnorm)
|
||||
public function __construct(
|
||||
\Illuminate\Routing\Redirector $redirect,
|
||||
Authenticator $authenticator,
|
||||
SocialNorm $socialnorm)
|
||||
{
|
||||
$this->redirect = $redirect;
|
||||
$this->authenticator = $authenticator;
|
||||
$this->socialnorm = $socialnorm;
|
||||
}
|
||||
|
||||
public function authorize($providerAlias)
|
||||
public function authorize(string $providerAlias)
|
||||
{
|
||||
return $this->redirect->to($this->socialnorm->authorize($providerAlias));
|
||||
}
|
||||
|
||||
public function login($providerAlias, $callback = null)
|
||||
/**
|
||||
* @param $providerAlias
|
||||
* @param \Closure|null $callback
|
||||
*/
|
||||
public function login(string $providerAlias, $callback = null)
|
||||
{
|
||||
$details = $this->socialnorm->getUser($providerAlias);
|
||||
return $this->authenticator->login($providerAlias, $details, $callback);
|
||||
}
|
||||
|
||||
public function registerProvider($alias, $provider)
|
||||
public function registerProvider(string $alias, Provider $provider)
|
||||
{
|
||||
$this->socialnorm->registerProvider($alias, $provider);
|
||||
}
|
||||
|
||||
@@ -4,20 +4,29 @@ use SocialNorm\Session as SocialNormSession;
|
||||
|
||||
class Session implements SocialNormSession
|
||||
{
|
||||
/** @var \Illuminate\Session\SessionManager */
|
||||
private $store;
|
||||
|
||||
public function __construct($store)
|
||||
public function __construct(\Illuminate\Session\SessionManager $store)
|
||||
{
|
||||
$this->store = $store;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
return $this->store->get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param mixed|null $value
|
||||
*/
|
||||
public function put($key, $value)
|
||||
{
|
||||
return $this->store->put($key, $value);
|
||||
$this->store->put($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,35 @@
|
||||
<?php namespace AdamWathan\EloquentOAuth;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class UserStore
|
||||
{
|
||||
protected $model;
|
||||
/** @var string */
|
||||
protected $modelClass;
|
||||
|
||||
public function __construct($model)
|
||||
public function __construct(string $modelClass)
|
||||
{
|
||||
$this->model = $model;
|
||||
$this->modelClass = $modelClass;
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$user = new $this->model;
|
||||
$user = new $this->modelClass;
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function store($user)
|
||||
public function store(Model $user)
|
||||
{
|
||||
return $user->save();
|
||||
}
|
||||
|
||||
public function findByIdentity($identity)
|
||||
public function findByIdentity(OAuthIdentity $identity)
|
||||
{
|
||||
return $identity->belongsTo($this->model, 'user_id')->firstOrFail();
|
||||
return $identity->belongsTo($this->modelClass, 'user_id')->firstOrFail();
|
||||
}
|
||||
|
||||
public function findByEmail(string $email)
|
||||
{
|
||||
return $this->modelClass::where('email', $email)->firstOrFail();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user