Viewing file: Gate.php (11.94 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
namespace Illuminate\Auth\Access;
use Illuminate\Support\Str; use InvalidArgumentException; use Illuminate\Contracts\Container\Container; use Illuminate\Contracts\Auth\Access\Gate as GateContract;
class Gate implements GateContract { use HandlesAuthorization;
/** * The container instance. * * @var \Illuminate\Contracts\Container\Container */ protected $container;
/** * The user resolver callable. * * @var callable */ protected $userResolver;
/** * All of the defined abilities. * * @var array */ protected $abilities = [];
/** * All of the defined policies. * * @var array */ protected $policies = [];
/** * All of the registered before callbacks. * * @var array */ protected $beforeCallbacks = [];
/** * All of the registered after callbacks. * * @var array */ protected $afterCallbacks = [];
/** * Create a new gate instance. * * @param \Illuminate\Contracts\Container\Container $container * @param callable $userResolver * @param array $abilities * @param array $policies * @param array $beforeCallbacks * @param array $afterCallbacks * @return void */ public function __construct(Container $container, callable $userResolver, array $abilities = [], array $policies = [], array $beforeCallbacks = [], array $afterCallbacks = []) { $this->policies = $policies; $this->container = $container; $this->abilities = $abilities; $this->userResolver = $userResolver; $this->afterCallbacks = $afterCallbacks; $this->beforeCallbacks = $beforeCallbacks; }
/** * Determine if a given ability has been defined. * * @param string $ability * @return bool */ public function has($ability) { return isset($this->abilities[$ability]); }
/** * Define a new ability. * * @param string $ability * @param callable|string $callback * @return $this * * @throws \InvalidArgumentException */ public function define($ability, $callback) { if (is_callable($callback)) { $this->abilities[$ability] = $callback; } elseif (is_string($callback) && Str::contains($callback, '@')) { $this->abilities[$ability] = $this->buildAbilityCallback($callback); } else { throw new InvalidArgumentException("Callback must be a callable or a 'Class@method' string."); }
return $this; }
/** * Create the ability callback for a callback string. * * @param string $callback * @return \Closure */ protected function buildAbilityCallback($callback) { return function () use ($callback) { list($class, $method) = explode('@', $callback);
return call_user_func_array([$this->resolvePolicy($class), $method], func_get_args()); }; }
/** * Define a policy class for a given class type. * * @param string $class * @param string $policy * @return $this */ public function policy($class, $policy) { $this->policies[$class] = $policy;
return $this; }
/** * Register a callback to run before all Gate checks. * * @param callable $callback * @return $this */ public function before(callable $callback) { $this->beforeCallbacks[] = $callback;
return $this; }
/** * Register a callback to run after all Gate checks. * * @param callable $callback * @return $this */ public function after(callable $callback) { $this->afterCallbacks[] = $callback;
return $this; }
/** * Determine if the given ability should be granted for the current user. * * @param string $ability * @param array|mixed $arguments * @return bool */ public function allows($ability, $arguments = []) { return $this->check($ability, $arguments); }
/** * Determine if the given ability should be denied for the current user. * * @param string $ability * @param array|mixed $arguments * @return bool */ public function denies($ability, $arguments = []) { return ! $this->allows($ability, $arguments); }
/** * Determine if the given ability should be granted for the current user. * * @param string $ability * @param array|mixed $arguments * @return bool */ public function check($ability, $arguments = []) { try { $result = $this->raw($ability, $arguments); } catch (AuthorizationException $e) { return false; }
return (bool) $result; }
/** * Determine if the given ability should be granted for the current user. * * @param string $ability * @param array|mixed $arguments * @return \Illuminate\Auth\Access\Response * * @throws \Illuminate\Auth\Access\AuthorizationException */ public function authorize($ability, $arguments = []) { $result = $this->raw($ability, $arguments);
if ($result instanceof Response) { return $result; }
return $result ? $this->allow() : $this->deny(); }
/** * Get the raw result for the given ability for the current user. * * @param string $ability * @param array|mixed $arguments * @return mixed */ protected function raw($ability, $arguments = []) { if (! $user = $this->resolveUser()) { return false; }
$arguments = is_array($arguments) ? $arguments : [$arguments];
if (is_null($result = $this->callBeforeCallbacks($user, $ability, $arguments))) { $result = $this->callAuthCallback($user, $ability, $arguments); }
$this->callAfterCallbacks( $user, $ability, $arguments, $result );
return $result; }
/** * Resolve and call the appropriate authorization callback. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param string $ability * @param array $arguments * @return bool */ protected function callAuthCallback($user, $ability, array $arguments) { $callback = $this->resolveAuthCallback( $user, $ability, $arguments );
return call_user_func_array( $callback, array_merge([$user], $arguments) ); }
/** * Call all of the before callbacks and return if a result is given. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param string $ability * @param array $arguments * @return bool|null */ protected function callBeforeCallbacks($user, $ability, array $arguments) { $arguments = array_merge([$user, $ability], [$arguments]);
foreach ($this->beforeCallbacks as $before) { if (! is_null($result = call_user_func_array($before, $arguments))) { return $result; } } }
/** * Call all of the after callbacks with check result. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param string $ability * @param array $arguments * @param bool $result * @return void */ protected function callAfterCallbacks($user, $ability, array $arguments, $result) { $arguments = array_merge([$user, $ability, $result], [$arguments]);
foreach ($this->afterCallbacks as $after) { call_user_func_array($after, $arguments); } }
/** * Resolve the callable for the given ability and arguments. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param string $ability * @param array $arguments * @return callable */ protected function resolveAuthCallback($user, $ability, array $arguments) { if ($this->firstArgumentCorrespondsToPolicy($arguments)) { return $this->resolvePolicyCallback($user, $ability, $arguments); } elseif (isset($this->abilities[$ability])) { return $this->abilities[$ability]; } else { return function () { return false; }; } }
/** * Determine if the first argument in the array corresponds to a policy. * * @param array $arguments * @return bool */ protected function firstArgumentCorrespondsToPolicy(array $arguments) { if (! isset($arguments[0])) { return false; }
if (is_object($arguments[0])) { return isset($this->policies[get_class($arguments[0])]); }
return is_string($arguments[0]) && isset($this->policies[$arguments[0]]); }
/** * Resolve the callback for a policy check. * * @param \Illuminate\Contracts\Auth\Authenticatable $user * @param string $ability * @param array $arguments * @return callable */ protected function resolvePolicyCallback($user, $ability, array $arguments) { return function () use ($user, $ability, $arguments) { $instance = $this->getPolicyFor($arguments[0]);
if (method_exists($instance, 'before')) { // We will prepend the user and ability onto the arguments so that the before // callback can determine which ability is being called. Then we will call // into the policy before methods with the arguments and get the result. $beforeArguments = array_merge([$user, $ability], $arguments);
$result = call_user_func_array( [$instance, 'before'], $beforeArguments );
// If we received a non-null result from the before method, we will return it // as the result of a check. This allows developers to override the checks // in the policy and return a result for all rules defined in the class. if (! is_null($result)) { return $result; } }
if (strpos($ability, '-') !== false) { $ability = Str::camel($ability); }
if (! is_callable([$instance, $ability])) { return false; }
return call_user_func_array( [$instance, $ability], array_merge([$user], $arguments) ); }; }
/** * Get a policy instance for a given class. * * @param object|string $class * @return mixed * * @throws \InvalidArgumentException */ public function getPolicyFor($class) { if (is_object($class)) { $class = get_class($class); }
if (! isset($this->policies[$class])) { throw new InvalidArgumentException("Policy not defined for [{$class}]."); }
return $this->resolvePolicy($this->policies[$class]); }
/** * Build a policy class instance of the given type. * * @param object|string $class * @return mixed */ public function resolvePolicy($class) { return $this->container->make($class); }
/** * Get a guard instance for the given user. * * @param \Illuminate\Contracts\Auth\Authenticatable|mixed $user * @return static */ public function forUser($user) { $callback = function () use ($user) { return $user; };
return new static( $this->container, $callback, $this->abilities, $this->policies, $this->beforeCallbacks, $this->afterCallbacks ); }
/** * Resolve the user from the user resolver. * * @return mixed */ protected function resolveUser() { return call_user_func($this->userResolver); } }
|