From 60f61f318b0a1e7ccf3897382c0aeb4688eec425 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 1 May 2012 10:50:33 -0500 Subject: [PATCH] refactored authentication system. --- laravel/auth.php | 233 ++++++++---------------------- laravel/auth/drivers/driver.php | 41 +++++- laravel/auth/drivers/eloquent.php | 74 ++++++++++ laravel/auth/drivers/fluent.php | 64 ++++++++ 4 files changed, 233 insertions(+), 179 deletions(-) create mode 100644 laravel/auth/drivers/eloquent.php create mode 100644 laravel/auth/drivers/fluent.php diff --git a/laravel/auth.php b/laravel/auth.php index bacd0863..b084ae69 100644 --- a/laravel/auth.php +++ b/laravel/auth.php @@ -3,214 +3,99 @@ class Auth { /** - * The current user of the application. + * The currently active authentication drivers. * - * @var object + * @var array */ - public static $user; + public static $drivers = array(); /** - * The key used when storing the user ID in the session. + * The third-party driver registrar. * - * @var string + * @var array */ - const user_key = 'laravel_user_id'; + public static $registrar = array(); /** - * Determine if the user of the application is not logged in. + * Get an authentication driver instance. * - * This method is the inverse of the "check" method. - * - * @return bool + * @param string $driver + * @return Driver */ - public static function guest() + public static function driver($driver = null) { - return ! static::check(); - } + if (is_null($driver)) $driver = Config::get('auth.driver'); - /** - * Determine if the user of the application is logged in. - * - * @return bool - */ - public static function check() - { - return ! is_null(static::user()); - } - - /** - * Get the current user of the application. - * - * - * // Get the current user of the application - * $user = Auth::user(); - * - * // Access a property on the current user of the application - * $email = Auth::user()->email; - * - * - * @return object|null - */ - public static function user() - { - if ( ! is_null(static::$user)) return static::$user; - - $id = Session::get(Auth::user_key); - - // To retrieve the user, we'll first attempt to use the "user" Closure - // defined in the auth configuration file, passing in the ID. The user - // Closure gives the developer a ton of freedom surrounding how the - // user is actually retrieved. - $config = Config::get('auth'); - - static::$user = call_user_func($config['user'], $id); - - // If the user wasn't found in the database but a "remember me" cookie - // exists, we'll attempt to recall the user based on the cookie value. - // Since all cookies contain a fingerprint hash verifying that they - // haven't changed, we can trust it. - $recaller = Cookie::get($config['cookie']); - - if (is_null(static::$user) and ! is_null($recaller)) + if ( ! isset(static::$drivers[$driver])) { - static::$user = static::recall($recaller); + static::$drivers[$driver] = static::factory($driver); } - return static::$user; + return static::$drivers[$driver]; } /** - * Attempt to login a user based on a long-lived "remember me" cookie. + * Create a new authentication driver instance. * - * @param string $recaller - * @return mixed + * @param string $driver + * @return Driver */ - protected static function recall($recaller) + protected static function factory($driver) { - $recaller = explode('|', Crypter::decrypt($recaller)); - - // We'll pass the ID that was stored in the cookie into the same user - // Closure that is used by the "user" method. If the method returns - // a user, we will log them into the application. - $user = call_user_func(Config::get('auth.user'), $recaller[0]); - - if ( ! is_null($user)) + if (isset(static::$registrar[$driver])) { - static::login($user); + return static::$registrar[$driver](); + } - return $user; + switch ($driver) + { + case 'fluent': + return new Auth\Drivers\Fluent(Config::get('auth.table')); + + case 'eloquent': + return new Auth\Drivers\Eloquent(Config::get('auth.model')); + + default: + throw new \Exception("Auth driver {$driver} is not supported."); } } /** - * Attempt to log a user into the application. - * - * - * // Attempt to log a user into the application - * $success = Auth::attempt('username', 'password'); - * - * // Attempt to login a user and set the "remember me" cookie - * Auth::attempt('username', 'password', true); - * - * - * @param string $username - * @param string $password - * @param bool $remember - * @return bool - */ - public static function attempt($username, $password = null, $remember = false) - { - $config = Config::get('auth'); - - // When attempting to login the user, we will call the "attempt" closure - // from the configuration file. This gives the developer the freedom to - // authenticate based on the needs of their application, even allowing - // the user of third-party providers. - $user = call_user_func($config['attempt'], $username, $password); - - if (is_null($user)) return false; - - static::login($user, $remember); - - return true; - } - - /** - * Log a user into the application. - * - * - * // Login the user with an ID of 15 - * Auth::login(15); - * - * // Login a user by passing a user object - * Auth::login($user); - * - * // Login a user and set a "remember me" cookie - * Auth::login($user, true); - * - * - * @param object|int $user - * @param bool $remember - * @return void - */ - public static function login($user, $remember = false) - { - $id = (is_object($user)) ? $user->id : (int) $user; - - if ($remember) static::remember($id); - - Session::put(Auth::user_key, $id); - } - - /** - * Set a cookie so that the user is "remembered". - * - * @param string $id - * @return void - */ - protected static function remember($id) - { - $recaller = Crypter::encrypt($id.'|'.Str::random(40)); - - // This method assumes the "remember me" cookie should have the same - // configuration as the session cookie. Since this cookie, like the - // session cookie, should be kept very secure, it's probably safe. - // to assume the cookie settings are the same. - $config = Config::get('session'); - - extract($config, EXTR_SKIP); - - $cookie = Config::get('auth.cookie'); - - Cookie::forever($cookie, $recaller, $path, $domain, $secure); - } - - /** - * Log the current user out of the application. + * Run the logout method on all active drivers. * * @return void */ public static function logout() { - // We will call the "logout" closure first, which gives the developer - // the chance to do any clean-up or before the user is logged out of - // the application. No action is taken by default. - call_user_func(Config::get('auth.logout'), static::user()); + array_walk(static::$drivers, function($d) { $d->logout(); }); + } - static::$user = null; + /** + * Register a third-party authentication driver. + * + * @param string $driver + * @param Closure $resolver + * @return void + */ + public static function extend($driver, Closure $resolver) + { + static::$registrar[$driver] = $resolver; + } - $config = Config::get('session'); - - extract($config, EXTR_SKIP); - - // When forgetting the cookie, we need to also pass in the path and - // domain that would have been used when the cookie was originally - // set by the framework, otherwise it will not be deleted. - $cookie = Config::get('auth.cookie'); - - Cookie::forget($cookie, $path, $domain, $secure); - - Session::forget(Auth::user_key); + /** + * Magic Method for calling the methods on the default cache driver. + * + * + * // Call the "user" method on the default auth driver + * $user = Auth::user(); + * + * // Call the "check" method on the default auth driver + * Auth::check(); + * + */ + public static function __callStatic($method, $parameters) + { + return call_user_func_array(array(static::driver(), $method), $parameters); } } \ No newline at end of file diff --git a/laravel/auth/drivers/driver.php b/laravel/auth/drivers/driver.php index d2725d79..652f5205 100644 --- a/laravel/auth/drivers/driver.php +++ b/laravel/auth/drivers/driver.php @@ -1,4 +1,4 @@ -check(); + } + /** * Determine if the user is logged in. * @@ -58,15 +70,28 @@ public function check() * * @return mixed|null */ - abstract public function user(); + public function user() + { + if ( ! is_null($this->user)) return $this->user; + + return $this->user = $this->retrieve($this->token); + } + + /** + * Get the a given application user by ID. + * + * @param int $id + * @return mixed + */ + abstract public function retrieve($id); /** * Attempt to log a user into the application. * - * @param dynamic $arguments + * @param array $arguments * @return void */ - abstract public function attempt(); + abstract public function attempt($arguments = array()); /** * Login the user assigned to the given token. @@ -74,10 +99,16 @@ abstract public function attempt(); * The token is typically a numeric ID for the user. * * @param string $token + * @param bool $remember + * @return bool */ - public function login($token) + public function login($token, $remember = false) { $this->store($token); + + if ($remember) $this->remember($token); + + return true; } /** diff --git a/laravel/auth/drivers/eloquent.php b/laravel/auth/drivers/eloquent.php new file mode 100644 index 00000000..38c2034b --- /dev/null +++ b/laravel/auth/drivers/eloquent.php @@ -0,0 +1,74 @@ +model = $model; + + parent::__construct(); + } + + /** + * Get the current user of the application. + * + * If the user is a guest, null should be returned. + * + * @param int $id + * @return mixed|null + */ + public function retrieve($id) + { + if (filter_var($id, FILTER_VALIDATE_INT) !== false) + { + return $this->model()->find($id); + } + } + + /** + * Attempt to log a user into the application. + * + * @param array $arguments + * @return void + */ + public function attempt($arguments = array()) + { + $user = $this->model()->where('email', '=', $arguments['email'])->first(); + + // This driver uses a basic username and password authentication scheme + // so if the credentials match what is in the database we will just + // log the user into the application and remember them if asked. + $password = $arguments['password']; + + if ( ! is_null($user) and Hash::check($password, $user->password)) + { + return $this->login($user->id, array_get($arguments, 'remember')); + } + + return false; + } + + /** + * Get a fresh model instance. + * + * @return Eloquent + */ + protected function model() + { + return new $this->model; + } + +} \ No newline at end of file diff --git a/laravel/auth/drivers/fluent.php b/laravel/auth/drivers/fluent.php new file mode 100644 index 00000000..909d9384 --- /dev/null +++ b/laravel/auth/drivers/fluent.php @@ -0,0 +1,64 @@ +table = $table; + + parent::__construct(); + } + + /** + * Get the current user of the application. + * + * If the user is a guest, null should be returned. + * + * @param int $id + * @return mixed|null + */ + public function retrieve($id) + { + if (filter_var($id, FILTER_VALIDATE_INT) !== false) + { + Database::table($this->table)->find($id); + } + } + + /** + * Attempt to log a user into the application. + * + * @param array $arguments + * @return void + */ + public function attempt($arguments = array()) + { + $user = Database::table($this->table)->where_email($arguments['email'])->first(); + + // This driver uses a basic username and password authentication scheme + // so if the credentials mmatch what is in the database we will just + // log the user into the application and remember them if asked. + $password = $arguments['password']; + + if ( ! is_null($user) and Hash::check($password, $user->password)) + { + return $this->login($user->id, array_get($arguments, 'remember')); + } + + return false; + } + +} \ No newline at end of file