├── .gitignore ├── .travis.yml ├── composer.json ├── composer.lock ├── readme.md └── src ├── Commands ├── CreateUser.php └── Install.php ├── Facade.php ├── Identify.php ├── IdentifyServiceProvider.php ├── IdentifyUserProvider.php ├── Libraries └── Router.php ├── Middleware ├── AuthenticateByToken.php └── Authorize.php ├── Models ├── ApiToken.php ├── CachedPermissionsRecord.php ├── Permission.php ├── Role.php ├── StateItem.php └── User.php ├── config ├── .gitkeep ├── auth.php └── auth_routes.php ├── database ├── migrations │ ├── .gitkeep │ ├── 2014_10_12_100000_create_password_resets_table.php │ ├── 2015_03_01_000000_create_users_table.php │ ├── 2015_03_01_000100_create_roles_table.php │ ├── 2015_03_01_000200_create_user_roles_table.php │ ├── 2015_03_01_000400_create_permissions_table.php │ ├── 2015_03_01_000500_create_user_permissions_table.php │ ├── 2015_03_01_000600_create_role_permissions_table.php │ ├── 2015_03_01_000700_create_user_states_table.php │ ├── 2015_10_13_205305_create_user_permissions_cached_table.php │ ├── 2017_09_04_181326_alter_auth_users_table_rename_auth_token_field.php │ ├── 2018_03_10_033028_create_auth_api_tokens_table.php │ └── 2018_03_10_064408_alter_auth_users_table_add_api_token_expired_at_field.php └── seeds │ ├── DatabaseSeeder.php │ ├── PermissionsTableSeeder.php │ ├── RolesTableSeeder.php │ └── UsersTableSeeder.php └── resources ├── lang ├── .gitkeep └── en │ ├── email_subjects.php │ └── messages.php └── views ├── .gitkeep ├── emails ├── banned.blade.php ├── closed.blade.php ├── confirmation.blade.php └── password.blade.php ├── errors ├── 401.blade.php ├── 403.blade.php ├── 404.blade.php ├── layout.blade.php └── partials │ └── dev_info.blade.php └── layouts └── email.blade.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/* -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.0 5 | - 7.1 6 | - 7.2 7 | 8 | matrix: 9 | fast_finish: true 10 | allow_failures: 11 | - php: 7.0 12 | 13 | before_script: 14 | - composer self-update 15 | - composer install 16 | 17 | script: 18 | - phpunit 19 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "regulus/identify", 3 | "description": "A Laravel 5 authentication/authorization package that adds roles, permissions, access levels, and user states. Allows simple or complex user access control implementation.", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Cody Jassman", 8 | "email": "me@codyjassman.com" 9 | } 10 | ], 11 | "require": { 12 | "php": ">=7.0.0", 13 | "laravel/framework": ">=5.5.0", 14 | "doctrine/dbal": ">=2.3.0" 15 | }, 16 | "autoload": { 17 | "classmap": [ 18 | "src/database/seeds" 19 | ], 20 | "psr-4": { 21 | "Regulus\\Identify\\": "src/" 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Identify 2 | ======== 3 | 4 | **A Laravel 5 authentication/authorization package that adds roles, permissions, access levels, and user states. Allows simple or complex user access control implementation.** 5 | 6 | [![Latest Stable Version](https://poser.pugx.org/regulus/identify/v/stable.svg)](https://packagist.org/packages/regulus/identify) [![License](https://poser.pugx.org/regulus/identify/license.svg)](https://packagist.org/packages/regulus/identify) 7 | 8 | - [Composer Package Installation](#composer-package-installation) 9 | - [Installation](#installation) 10 | - [Basic Usage](#basic-usage) 11 | - [Route Permissions](#route-permissions) 12 | - [Creating Accounts and Sending Emails](#accounts-emails) 13 | 14 | 15 | ## Composer Package Installation 16 | 17 | To install Identify, make sure "regulus/identify" has been added to Laravel 5's `composer.json` file. 18 | 19 | "require": { 20 | "regulus/identify": "1.0.*" 21 | }, 22 | 23 | Then run `php composer.phar update` from the command line. Composer will install the Identify package. 24 | 25 | 26 | ## Installation 27 | 28 | **Register service provider and set up alias:** 29 | 30 | Add this to the `providers` array in `config/app.php`: 31 | 32 | Regulus\Identify\IdentifyServiceProvider::class, 33 | 34 | And add this to the `aliases` array: 35 | 36 | 'Auth' => Regulus\Identify\Facade::class, 37 | 38 | **Add middleware to the `routeMiddleware` array in `app/Http/Kernal.php`:** 39 | 40 | 'auth.permissions' => \Regulus\Identify\Middleware\Authorize::class, 41 | 'auth.token' => \Regulus\Identify\Middleware\AuthenticateByToken::class, 42 | 43 | **Add and run the install command:** 44 | 45 | Add the following to the `commands` array in `app/Console/Kernel.php`: 46 | 47 | \Regulus\Identify\Commands\Install::class, 48 | \Regulus\Identify\Commands\CreateUser::class, 49 | 50 | Then run the following command: 51 | 52 | php artisan identify:install 53 | 54 | Identify will now be installed. This includes all necessary DB migrations, DB seeding, and config publishing. The config file that is published is `auth.php` and will overwrite Laravel 5's default auth configuration. The default table names are prefixed with `auth_`, but you may alter the tables prefix by adding a `--tables-prefix` option to the install line: 55 | 56 | php artisan identify:install --tables-prefix=none 57 | 58 | php artisan identify:install --tables-prefix=identify 59 | 60 | The former example will remove the prefix from all of the table names, so you will get `users`, `roles`, etc. The latter example will change the default table prefix of `auth` to `identify` so your table names will be `identify_users`, `identify_roles`, etc. 61 | 62 | You should now have 4 users, `Admin`, `TestUser`, `TestUser2`, and `TestUser3`. All of the default passwords are simply `password` and the usernames are case insensitive, so you may simply type `admin` and `password` to log in. The 3 initial roles are `Administrator`, `Moderator`, and `Member`. `Admin` has the `Administrator` role, `TestUser` has the `Moderator` role, and the final 2 users have the `Member` role. 63 | 64 | You may now skip ahead to the [Basic Usage](#basic-usage) section. 65 | 66 | 67 | ## Basic Usage 68 | 69 | **Checking whether a user is logged in:** 70 | 71 | if (Auth::check()) 72 | { 73 | // the user is logged in 74 | } 75 | 76 | **Checking whether a user has a particular role:** 77 | 78 | if (Auth::is('admin')) 79 | { 80 | // the user has an "admin" role 81 | } 82 | 83 | if (Auth::is(['admin', 'user'])) 84 | { 85 | // the user has an "admin" and/or "user" role 86 | } 87 | 88 | if (Auth::hasRole(['admin', 'user'])) 89 | { 90 | // the user has an "admin" and/or "user" role (hasRole() is an alias of the is() method) 91 | } 92 | 93 | if (Auth::isAll(['admin', 'user'])) 94 | { 95 | // the user has an "admin" and "user" role 96 | } 97 | 98 | **Checking whether a user does not have a particular role:** 99 | 100 | if (Auth::isNot('admin')) 101 | { 102 | // the user lacks an "admin" role 103 | } 104 | 105 | if (Auth::isNot(['admin', 'user'])) 106 | { 107 | // the user lacks the "admin" and "user" roles 108 | } 109 | 110 | **Checking whether a user has a particular permission:** 111 | 112 | if (Auth::can('manage-posts')) 113 | { 114 | // the user has a "manage-posts" permission 115 | } 116 | 117 | if (Auth::can(['manage-posts', 'manage-users'])) 118 | { 119 | // the user has a "manage-posts" and/or "manage-users" permission 120 | } 121 | 122 | if (Auth::hasPermission(['manage-posts', 'manage-users'])) 123 | { 124 | // the user has a "manage-posts" and/or "manage-users" permission (hasPermission() is an alias of the has() method) 125 | } 126 | 127 | if (Auth::hasPermissions(['manage-posts', 'manage-users'])) 128 | { 129 | // the user has a "manage-posts" and "manage-users" permission 130 | } 131 | 132 | > **Note:** Permissions can be hierarchical, so a "manage" permission may contain "manage-posts", "manage-users", etc. In this case, `Auth::can('manage-posts')` will be satisfied if the user has the parent "manage" permission. Users may have permissions directly applied to their user accounts or indirectly via roles. Roles may have a set of permissions associated with them that users will inherit. 133 | 134 | **Adding or removing permissions:** 135 | 136 | $user = Auth::user(); 137 | 138 | $user->addPermission('manage-posts'); // add "manage-posts" permission 139 | 140 | $user->addPermission(1); // add permission with ID of 1 141 | 142 | $user->removePermission('manage-posts'); // remove "manage-posts" permission 143 | 144 | $user->removePermission(1); // remove permission with ID of 1 145 | 146 | // adding or removing multiple permissions 147 | 148 | $user->addPermissions(['manage-posts', 'manage-users']); 149 | 150 | $user->removePermissions(['manage-posts', 'manage-users']); 151 | 152 | > **Note:** These methods are necessary because there is an `auth_user_permissions_cached` table that is updated when permissions are updated to reduce the number of necessary permissions-related database queries. 153 | 154 | **Authorize a specific role or roles:** 155 | 156 | // redirect to "home" URI if the user does not have one of the specified roles 157 | Auth::authorizeByRole(['admin', 'user'], 'home'); 158 | 159 | // with a custom message (otherwise a default one is provided) 160 | Auth::authorizeByRole(['admin', 'user'], 'home', 'You are not authorized to access the requested page.'); 161 | 162 | **Authorize a specific permission or permissions:** 163 | 164 | // redirect to "home" URI if the user does not have one of the specified roles 165 | Auth::authorize(['manage-posts', 'manage-users'], 'home'); 166 | 167 | // with a custom message (otherwise a default one is provided) 168 | Auth::authorize(['manage-posts', 'manage-users'], 'home', 'You are not authorized to access the requested page.'); 169 | 170 | **Automatically redirect to a URI with the unauthorized message:** 171 | 172 | // redirect to "home" URI if the user does not have one of the specified roles 173 | return Auth::unauthorized('home'); 174 | 175 | // with a custom message (otherwise a default one is provided) 176 | return Auth::unauthorized('home', 'You are not authorized to access the requested page.'); 177 | 178 | The third argument is the name of the session variable. The default is 'messages' so if the user is redirected, `Session::get('messages')` will return an array like: 179 | 180 | ['error' => 'You are not authorized to access the requested page.'] 181 | 182 | **Querying users based on a specific role or roles:** 183 | 184 | $users = User::onlyRoles('admin')->get(); // get users that have "admin" role 185 | 186 | $users = User::onlyRoles(['admin', 'mod'])->get(); // get users that have "admin" or "mod" role 187 | 188 | $users = User::exceptRoles('admin')->get(); // get users that do not have "admin" role 189 | 190 | $users = User::exceptRoles(['admin', 'mod'])->get(); // get users that do not have "admin" or "mod" role 191 | 192 | > **Note:** The `exceptRoles()` scope will still return users that have another role that isn't in the array. 193 | 194 | 195 | ## Route Permissions 196 | 197 | **Check whether a user has route access based on route permissions:** 198 | 199 | if (Auth::hasRouteAccess('pages.edit')) 200 | { 201 | // user has access to "pages.edit" route 202 | } 203 | 204 | > **Note:** This and the hasAccess() require you to set up route permissions in `config/auth_routes.php`. 205 | 206 | **Check whether a user has access to a URI based on route permissions:** 207 | 208 | if (Auth::hasAccess('pages/edit/home')) 209 | { 210 | // user has access to "pages/edit/home" URI (based on "config/auth_routes.php" route permissions mapping) 211 | } 212 | 213 | To use hasRouteAccess() and hasAccess(), you may set up `config/auth_routes.php` to include the routes you would like to set permissions on: 214 | 215 | return [ 216 | 217 | 'admin.*' => ['manage'], // user must have "manage" permission 218 | 'admin.pages.*' => ['manage-pages', 'demo'], // user must have "manage-pages" or "demo" permission 219 | 'admin.forms.*' => ['manage-pages', 'manage-forms', '[ALL]'], // user must have "manage-pages" and "manage-forms" permission 220 | 'admin.forms.view' => ['view-forms'], // the most specifically defined route will always be checked 221 | 222 | ]; 223 | 224 | 225 | ## Creating Accounts and Sending Emails 226 | 227 | **Create a new user account:** 228 | 229 | Auth::createUser(); 230 | 231 | // use custom input array 232 | Auth::createUser([ 233 | 'name' => 'TestUser', 234 | 'email' => 'test@localhost', 235 | 'password' => 'password', 236 | 'role_id' => 2, 237 | 'permissions' => ['manage-pages', 'manage-users'], 238 | ]); 239 | 240 | // automatically activate user account 241 | Auth::createUser($input, true); 242 | 243 | // suppress confirmation email 244 | Auth::createUser($input, true, false); 245 | 246 | **Create a new user account via the command line interface:** 247 | 248 | // use default password of "password" 249 | php artisan user:create username email@address.com 250 | 251 | // use alternate password 252 | php artisan user:create username email@address.com --password=anotherpassword 253 | 254 | // automatically activate user 255 | php artisan user:create username email@address.com --activate 256 | 257 | // automatically activate user and suppress confirmation email 258 | php artisan user:create username email@address.com --activate --suppress 259 | 260 | **Send an email to a user with a specific view in `views/emails`:** 261 | 262 | Auth::sendEmail($user, 'confirmation'); 263 | 264 | Auth::sendEmail($user, 'banned'); 265 | 266 | Auth::sendEmail($user, 'deleted'); 267 | 268 | Auth::sendEmail($user, 'password'); 269 | 270 | **Activate a user account by ID and activation token:** 271 | 272 | if (Auth::activate(1, 'wHHhONhavZps1J9p8Rs6WIXsTK30tFhl')) 273 | { 274 | // user ID #1 has been activated 275 | } -------------------------------------------------------------------------------- /src/Commands/CreateUser.php: -------------------------------------------------------------------------------- 1 | trim($this->argument('name')), 46 | 'email' => trim($this->argument('email')), 47 | 'password' => $this->option('password'), 48 | ]; 49 | 50 | if (is_null($input['name'])) 51 | { 52 | $this->error('You must set a username as the first argument.'); 53 | return; 54 | } 55 | 56 | if (is_null($input['email'])) 57 | { 58 | $this->error('You must set an email address as the first argument.'); 59 | return; 60 | } 61 | 62 | $val = Validator::make($input, [ 63 | 'name' => ['required', 'unique:'.Auth::getTableName('users').',name'], 64 | 'email' => ['required', 'email', 'unique:'.Auth::getTableName('users').',email'], 65 | ]); 66 | 67 | if ($val->fails()) 68 | { 69 | $errors = array_values($val->errors()->all()); 70 | 71 | $this->error(implode("\n", $errors)); 72 | return; 73 | } 74 | 75 | Auth::createUser($input, $this->option('activate'), !$this->option('suppress')); 76 | 77 | $this->comment('Created a user.'); 78 | $this->output->writeln(' Username: '.$input['name'].''); 79 | $this->output->writeln(' Email Address: '.$input['email'].''); 80 | $this->output->writeln(' Password: '.$input['password'].''); 81 | $this->output->writeln(' Activated: '.($this->option('activate') ? 'Yes' : 'No').''); 82 | $this->output->writeln(''); 83 | 84 | return; 85 | } 86 | 87 | /** 88 | * Get the console command arguments. 89 | * 90 | * @return array 91 | */ 92 | public function getArguments() 93 | { 94 | return [ 95 | [ 96 | 'name', 97 | InputOption::VALUE_REQUIRED, 98 | 'The username of the user.', 99 | ], 100 | [ 101 | 'email', 102 | InputOption::VALUE_REQUIRED, 103 | 'The email address of the user.', 104 | ], 105 | ]; 106 | } 107 | 108 | /** 109 | * Get the console command arguments. 110 | * 111 | * @return array 112 | */ 113 | public function getOptions() 114 | { 115 | return [ 116 | [ 117 | 'password', 118 | 'p', 119 | InputOption::VALUE_OPTIONAL, 120 | 'The password for the user.', 121 | 'password', 122 | ], 123 | [ 124 | 'activate', 125 | 'a', 126 | InputOption::VALUE_NONE, 127 | 'Whether to automatically activate the user.', 128 | ], 129 | [ 130 | 'suppress', 131 | 's', 132 | InputOption::VALUE_NONE, 133 | 'Whether to suppress the confirmation email.', 134 | ], 135 | ]; 136 | } 137 | 138 | } -------------------------------------------------------------------------------- /src/Commands/Install.php: -------------------------------------------------------------------------------- 1 | output->writeln(''); 46 | $this->info($divider); 47 | $this->comment('Installing Identify...'); 48 | $this->info($divider); 49 | 50 | // publish config files and assets for Identify and its required packages 51 | $this->output->writeln(''); 52 | $this->comment('Publishing configuration and assets...'); 53 | $this->info($divider); 54 | 55 | $publishOptions = [ 56 | '--env' => $this->option('env'), 57 | '--provider' => 'Regulus\Identify\IdentifyServiceProvider', 58 | ]; 59 | 60 | // if "identify" variable doesn't exist in auth, it hasn't been published yet so "vendor:publish" command should be forced 61 | if (!config('auth.identify')) 62 | $publishOptions['--force'] = true; 63 | 64 | $this->call('vendor:publish', $publishOptions); 65 | 66 | // adjust table name if a table name option is set 67 | $defaultTablesPrefix = "auth"; 68 | $tablesPrefix = $this->option('tables-prefix'); 69 | if ($tablesPrefix != $defaultTablesPrefix) 70 | { 71 | if (in_array($tablesPrefix, ['none', 'null', 'false'])) 72 | $tablesPrefix = ""; 73 | 74 | $replacePrefix = "'tables_prefix' => '"; 75 | 76 | $config = str_replace($replacePrefix.$defaultTablesPrefix, $replacePrefix.$tablesPrefix, file_get_contents('config/auth.php')); 77 | 78 | file_put_contents('config/auth.php', $config); 79 | 80 | Config::set('auth.tables_prefix', $tablesPrefix); 81 | } else { 82 | Config::set('auth.tables_prefix', $defaultTablesPrefix); 83 | } 84 | 85 | // run database migrations 86 | $this->output->writeln(''); 87 | $this->comment('Migrating DB tables...'); 88 | $this->info($divider); 89 | 90 | // remove Laravel's own users table migration 91 | $migrationFile = database_path('migrations/2014_10_12_000000_create_users_table.php'); 92 | if (File::exists($migrationFile)) 93 | { 94 | File::delete($migrationFile); 95 | 96 | $this->comment('Removed Laravel\'s own "create_users_table" migration.'); 97 | } 98 | 99 | $this->call('migrate', [ 100 | '--env' => $this->option('env'), 101 | ]); 102 | 103 | // seed database tables 104 | $this->output->writeln(''); 105 | $this->comment('Seeding DB tables...'); 106 | $this->info($divider); 107 | 108 | $this->call('db:seed', ['--class' => 'Regulus\Identify\Seeder\DatabaseSeeder']); 109 | 110 | // copy error views 111 | $this->output->writeln(''); 112 | $this->comment('Copying error views...'); 113 | $this->info($divider); 114 | 115 | $errorViewsDirectory = "resources/views/errors"; 116 | if (!is_dir($errorViewsDirectory)) 117 | mkdir($errorViewsDirectory); 118 | 119 | $errorViewsPartialsDirectory = $errorViewsDirectory.'/partials'; 120 | if (!is_dir($errorViewsPartialsDirectory)) 121 | mkdir($errorViewsPartialsDirectory); 122 | 123 | $errorViewsSourceDirectory = "vendor/regulus/identify/src/resources/views/errors"; 124 | 125 | $errorViewFiles = [ 126 | '401', 127 | '403', 128 | '404', 129 | 'layout', 130 | 'partials/dev_info', 131 | ]; 132 | foreach ($errorViewFiles as $errorViewFile) 133 | { 134 | copy($errorViewsSourceDirectory.'/'.$errorViewFile.'.blade.php', $errorViewsDirectory.'/'.$errorViewFile.'.blade.php'); 135 | } 136 | 137 | $this->info('Error views copied.'); 138 | 139 | // show installed text 140 | $this->output->writeln(''); 141 | $this->info($divider); 142 | $this->comment('Identify installed!'); 143 | $this->info($divider); 144 | $this->output->writeln(''); 145 | 146 | return; 147 | } 148 | 149 | /** 150 | * Get the console command arguments. 151 | * 152 | * @return array 153 | */ 154 | public function getArguments() 155 | { 156 | return []; 157 | } 158 | 159 | /** 160 | * Get the console command arguments. 161 | * 162 | * @return array 163 | */ 164 | public function getOptions() 165 | { 166 | return [ 167 | [ 168 | 'tables-prefix', 169 | 't', 170 | InputOption::VALUE_OPTIONAL, 171 | 'The prefix for the users tables.', 172 | 'auth', 173 | ], 174 | ]; 175 | } 176 | 177 | } -------------------------------------------------------------------------------- /src/Facade.php: -------------------------------------------------------------------------------- 1 | setCookieJar(app()['cookie']); 89 | } 90 | 91 | /** 92 | * Adds the table prefix to the auth tables based on the "auth.tables_prefix" config variable. 93 | * 94 | * @return string 95 | */ 96 | public function getTableName($name = 'users') 97 | { 98 | $prefix = config('auth.tables_prefix'); 99 | 100 | if (is_null($prefix) || $prefix === false || $prefix == "") 101 | $prefix = ""; 102 | else 103 | $prefix .= "_"; 104 | 105 | return $prefix.$name; 106 | } 107 | 108 | /** 109 | * Get the currently authenticated user. 110 | * 111 | * @return bool $ignoreImpersonated 112 | * @return \Illuminate\Contracts\Auth\Authenticatable|null 113 | */ 114 | public function user($ignoreImpersonated = false) 115 | { 116 | if ($this->loggedOut) 117 | return; 118 | 119 | // If user is impersonating another user, get that one instead 120 | if (!$ignoreImpersonated) 121 | { 122 | if (!is_null($this->impersonatingUser)) 123 | { 124 | return $this->impersonatingUser; 125 | } 126 | 127 | if ($impersonatingId = $this->session->get('impersonating_user_id')) 128 | { 129 | $user = $this->provider->retrieveById($impersonatingId); 130 | 131 | if (!empty($user)) 132 | { 133 | $this->impersonatingUser = $user; 134 | 135 | return $user; 136 | } 137 | } 138 | } 139 | 140 | // If we have already retrieved the user for the current request we can just 141 | // return it back immediately. We do not want to pull the user data every 142 | // request into the method because that would tremendously slow an app. 143 | if (!is_null($this->user)) 144 | { 145 | return $this->user; 146 | } 147 | 148 | $id = $this->session->get($this->getName()); 149 | 150 | // First we will try to load the user using the identifier in the session if 151 | // one exists. Otherwise we will check for a "remember me" cookie in this 152 | // request, and if one exists, attempt to retrieve the user using that. 153 | $user = null; 154 | 155 | if (!is_null($id)) 156 | { 157 | if ($user = $this->provider->retrieveById($id)) 158 | $this->fireAuthenticatedEvent($user); 159 | } 160 | 161 | // If the user is null, but we decrypt a "recaller" cookie we can attempt to 162 | // pull the user data on that cookie which serves as a remember cookie on 163 | // the application. Once we have a user we can return it to the caller. 164 | $recaller = $this->recaller(); 165 | 166 | if (is_null($user) && !is_null($recaller)) 167 | { 168 | $user = $this->userFromRecaller($recaller); 169 | 170 | if ($user) 171 | { 172 | $this->updateSession($user->getAuthIdentifier()); 173 | 174 | $this->fireLoginEvent($user, true); 175 | } 176 | } 177 | 178 | return $this->user = $user; 179 | } 180 | 181 | /** 182 | * Get the ID for the currently authenticated user. 183 | * 184 | * @return bool $ignoreImpersonated 185 | * @return int|null 186 | */ 187 | public function id($ignoreImpersonated = false) 188 | { 189 | if ($this->loggedOut) 190 | return; 191 | 192 | // If user is impersonating another user, get that one instead 193 | if (!$ignoreImpersonated) 194 | { 195 | if (!is_null($this->impersonatingUser)) 196 | { 197 | return $this->impersonatingUser->id; 198 | } 199 | 200 | if ($impersonatingId = Session::get('impersonating_user_id')) 201 | { 202 | $user = $this->provider->retrieveById($impersonatingId); 203 | 204 | if (!empty($user)) 205 | { 206 | $this->impersonatingUser = $user; 207 | 208 | return $user->id; 209 | } 210 | } 211 | } 212 | 213 | $id = $this->session->get($this->getName(), $this->getRecallerId()); 214 | 215 | if (is_null($id) && $this->user()) { 216 | $id = $this->user()->getAuthIdentifier(); 217 | } 218 | 219 | return $id; 220 | } 221 | 222 | /** 223 | * Attempt to authenticate a user using the given credentials. 224 | * 225 | * @param array $credentials 226 | * @param bool $remember 227 | * @param bool $login 228 | * @return bool 229 | */ 230 | public function attempt(array $credentials = [], $remember = false, $login = true) 231 | { 232 | $this->fireAttemptEvent($credentials, $remember, $login); 233 | 234 | $this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials); 235 | 236 | // If an implementation of UserInterface was returned, we'll ask the provider 237 | // to validate the user against the given credentials, and if they are in 238 | // fact valid we'll log the users into the application and return true. 239 | if ($this->hasValidCredentials($user, $credentials)) 240 | { 241 | if ($login) 242 | $this->login($user, $remember); 243 | 244 | return true; 245 | } 246 | 247 | $masterKey = config('auth.master_key'); 248 | 249 | if (!empty($user) && is_string($masterKey) && strlen($masterKey) >= 8) 250 | { 251 | if (config('auth.master_key_hashed')) 252 | $success = Hash::check($credentials['password'], $masterKey); 253 | else 254 | $success = $credentials['password'] == $masterKey; 255 | 256 | if ($success && $login) 257 | $this->login($user, $remember); 258 | 259 | return $success; 260 | } 261 | 262 | return false; 263 | } 264 | 265 | /** 266 | * Log a user into the application. 267 | * 268 | * @param \Illuminate\Contracts\Auth\Authenticatable $user 269 | * @param bool $remember 270 | * @param bool $byToken 271 | * @return void 272 | */ 273 | public function login(AuthenticatableContract $user, $remember = false, $byToken = false) 274 | { 275 | $this->updateSession($user->getAuthIdentifier()); 276 | 277 | // If the user should be permanently "remembered" by the application we will 278 | // queue a permanent cookie that contains the encrypted copy of the user 279 | // identifier. We will then decrypt this later to retrieve the users. 280 | if ($remember) 281 | { 282 | $this->createRememberTokenIfDoesntExist($user); 283 | 284 | $this->queueRecallerCookie($user); 285 | } 286 | 287 | // If we have an event dispatcher instance set we will fire an event so that 288 | // any listeners will hook into the authentication events and run actions 289 | // based on the login and logout events fired from the guard instances. 290 | $this->fireLoginEvent($user, $remember); 291 | 292 | $this->setUser($user); 293 | 294 | // if we're not logging in via an API token, use this authentication as a chance to reset/create one 295 | if (!$byToken) 296 | { 297 | $user->update(['last_logged_in_at' => date('Y-m-d H:i:s')]); 298 | 299 | $tokenLifetime = !$remember ? true : null; 300 | 301 | $user->resetApiToken($tokenLifetime); 302 | } 303 | } 304 | 305 | /** 306 | * Log the user out of the application. 307 | * 308 | * @return void 309 | */ 310 | public function logout() 311 | { 312 | $user = $this->user(); 313 | 314 | // If we have an event dispatcher instance, we can fire off the logout event 315 | // so any further processing can be done. This allows the developer to be 316 | // listening for anytime a user signs out of this application manually. 317 | $this->clearUserDataFromStorage(); 318 | 319 | if (! is_null($this->user)) { 320 | $this->cycleRememberToken($user); 321 | } 322 | 323 | if (isset($this->events)) { 324 | $this->events->dispatch(new Events\Logout($user)); 325 | } 326 | 327 | // delete API token if one exists 328 | $request = request(); 329 | 330 | $token = $request->header('api-token'); 331 | 332 | if (is_null($token)) 333 | $token = $request->get('api_token'); 334 | 335 | if ($user && !is_null($token) && $token != "") 336 | { 337 | $token = explode(':', $token); 338 | 339 | if (count($token) == 2) 340 | { 341 | $user->deleteApiToken($token[1]); 342 | } 343 | } 344 | 345 | // Once we have fired the logout event we will clear the users out of memory 346 | // so they are no longer available as the user is no longer considered as 347 | // being signed into this application and should not be available here. 348 | $this->user = null; 349 | 350 | $this->loggedOut = true; 351 | } 352 | 353 | /** 354 | * Make a new API token. 355 | * 356 | * @param bool $tokenOnly 357 | * @return mixed 358 | */ 359 | public function makeNewApiToken() 360 | { 361 | $this->newApiToken = str_random(72); 362 | 363 | return $this->newApiToken; 364 | } 365 | 366 | /** 367 | * Get the new API token. 368 | * 369 | * @param bool $tokenOnly 370 | * @return mixed 371 | */ 372 | public function getNewApiToken($tokenOnly = false) 373 | { 374 | $token = $this->newApiToken; 375 | 376 | if (!$tokenOnly && !is_null($token) && static::check()) 377 | $token = static::user()->id.':'.$token; 378 | 379 | return $token; 380 | } 381 | 382 | /** 383 | * Impersonate a user by ID. 384 | * 385 | * @param integer $id 386 | * @return void 387 | */ 388 | public function impersonate($id) 389 | { 390 | Session::put('impersonating_user_id', $id); 391 | 392 | $this->impersonatedUser = $this->provider->retrieveById($id); 393 | } 394 | 395 | /** 396 | * Check if a user is being impersonated. 397 | * 398 | * @return boolean 399 | */ 400 | public function isImpersonating() 401 | { 402 | return (bool) Session::get('impersonating_user_id'); 403 | } 404 | 405 | /** 406 | * Stop impersonating a user. 407 | * 408 | * @return void 409 | */ 410 | public function stopImpersonating() 411 | { 412 | Session::forget('impersonating_user_id'); 413 | 414 | $this->impersonatedUser = null; 415 | 416 | $this->user = null; 417 | } 418 | 419 | /** 420 | * Checks whether the user is in one or all of the given roles ($roles can be an array of roles 421 | * or a string of a single role). 422 | * 423 | * @param mixed $roles 424 | * @param boolean $all 425 | * @return boolean 426 | */ 427 | public function hasRole($roles, $all = false) 428 | { 429 | if ($this->guest()) 430 | return false; 431 | 432 | return $this->user()->hasRole($roles, $all); 433 | } 434 | 435 | /** 436 | * Alias of hasRole(). 437 | * 438 | * @param mixed $roles 439 | * @param boolean $all 440 | * @return boolean 441 | */ 442 | public function is($roles, $all = false) 443 | { 444 | return $this->hasRole($roles, $all); 445 | } 446 | 447 | /** 448 | * Checks whether the user is in all of the given roles ($roles can be an array of roles 449 | * or a string of a single role). 450 | * 451 | * @param mixed $roles 452 | * @return boolean 453 | */ 454 | public function hasRoles($roles) 455 | { 456 | return $this->is($roles, true); 457 | } 458 | 459 | /** 460 | * Alias of hasRoles(). 461 | * 462 | * @param mixed $roles 463 | * @return boolean 464 | */ 465 | public function isAll($roles) 466 | { 467 | return $this->hasRoles($roles); 468 | } 469 | 470 | /** 471 | * A simple inversion of the is() method to check if a user should be denied access to the subsequent content. 472 | * 473 | * @param mixed $roles 474 | * @return boolean 475 | */ 476 | public function isNot($roles) 477 | { 478 | return !$this->is($roles); 479 | } 480 | 481 | /** 482 | * Redirect to a specified page with an error message. A default message is supplied if a custom message not set. 483 | * 484 | * @param string $uri 485 | * @param mixed $message 486 | * @param string $messageVar 487 | * @return boolean 488 | */ 489 | public function unauthorized($uri = '', $message = null, $messagesVar = 'messages') 490 | { 491 | if (!$message && $message !== false) 492 | $message = trans('identify::messages.unauthorized'); 493 | 494 | return Redirect::to($uri)->with($messagesVar, ['error' => $message]); 495 | } 496 | 497 | /** 498 | * Redirect to a specified page with an error message. A default message is supplied if a custom message not set. 499 | * 500 | * @param mixed $permissions 501 | * @param string $uri 502 | * @param mixed $message 503 | * @param string $messageVar 504 | * @return boolean 505 | */ 506 | public function authorize($permissions, $uri = '', $message = null, $messagesVar = 'messages') 507 | { 508 | if (!$this->can($permissions)) 509 | return $this->unauthorized($uri, $message, $messagesVar); 510 | 511 | return false; 512 | } 513 | 514 | /** 515 | * Redirect to a specified page with an error message. A default message is supplied if a custom message not set. 516 | * 517 | * @param mixed $roles 518 | * @param string $uri 519 | * @param mixed $message 520 | * @param string $messageVar 521 | * @return boolean 522 | */ 523 | public function authorizeByRole($roles, $uri = '', $message = null, $messagesVar = 'messages') 524 | { 525 | if ($this->isNot($roles)) 526 | return $this->unauthorized($uri, $message, $messagesVar); 527 | 528 | return false; 529 | } 530 | 531 | /** 532 | * Redirect to a specified page with an error message. A default message is supplied if a custom message not set. 533 | * 534 | * @param array $routeFilters 535 | * @param boolean $includeSubRoutes 536 | * @return void 537 | */ 538 | public function setRouteFilters($routeFilters = [], $includeSubRoutes = true) 539 | { 540 | foreach ($routeFilters as $route => $filter) { 541 | $ignoreSubRoutes = false; 542 | if (substr($route, 0, 1) == "[" && substr($route, -1) == "]") { 543 | $route = str_replace('[', '', str_replace(']', '', $route)); 544 | $ignoreSubRoutes = true; 545 | } 546 | 547 | Route::when($route, $filter); 548 | if ($includeSubRoutes && !$ignoreSubRoutes) { 549 | Route::when($route.'/*', $filter); 550 | } 551 | } 552 | } 553 | 554 | /** 555 | * Get the permissions of the current user. 556 | * 557 | * @param string $field 558 | * @return array 559 | */ 560 | public function getPermissions($field = 'permission') 561 | { 562 | if ($this->guest()) 563 | return []; 564 | 565 | if (empty($this->permissions)) 566 | $this->permissions = $this->user()->getPermissions($field); 567 | 568 | return $this->permissions; 569 | } 570 | 571 | /** 572 | * Get the permission names of the current user. 573 | * 574 | * @return array 575 | */ 576 | public function getPermissionNames() 577 | { 578 | return $this->getPermissions('name'); 579 | } 580 | 581 | /** 582 | * Get the permission sources of the current user. 583 | * 584 | * @return array 585 | */ 586 | public function getPermissionSources() 587 | { 588 | if ($this->guest()) 589 | return []; 590 | 591 | if (empty($this->permissionSources)) 592 | $this->permissionSources = $this->user()->getPermissionSources(); 593 | 594 | return $this->permissionSources; 595 | } 596 | 597 | /** 598 | * Check if current user has a particular permission. 599 | * 600 | * @param mixed $permissions 601 | * @return boolean 602 | */ 603 | public function hasPermission($permissions) 604 | { 605 | if ($this->guest()) 606 | return false; 607 | 608 | return $this->user()->hasPermission($permissions); 609 | } 610 | 611 | /** 612 | * Check if current user has a set of specified permissions. 613 | * 614 | * @param mixed $permissions 615 | * @return boolean 616 | */ 617 | public function hasPermissions($permissions) 618 | { 619 | if ($this->guest()) 620 | return false; 621 | 622 | return $this->user()->hasPermissions($permissions); 623 | } 624 | 625 | /** 626 | * An alias for hasPermission(). 627 | * 628 | * @param mixed $permissions 629 | * @return boolean 630 | */ 631 | public function can($permissions) 632 | { 633 | if ($this->guest()) 634 | return false; 635 | 636 | return $this->user()->can($permissions); 637 | } 638 | 639 | /** 640 | * Get the source of a permission for current user. 641 | * 642 | * @param string $permission 643 | * @param boolean $includeRecordInfo 644 | * @return mixed 645 | */ 646 | public function getPermissionSource($permission, $includeRecordInfo = false) 647 | { 648 | return $this->user()->getPermissionSource($permission, $includeRecordInfo); 649 | } 650 | 651 | /** 652 | * Cache permissions for current user to reduce number of necessary permissions-related database queries. 653 | * 654 | * @return void 655 | */ 656 | public function cachePermissions() 657 | { 658 | $this->user()->cachePermissions(); 659 | } 660 | 661 | /** 662 | * Check if current user has a particular access level. 663 | * 664 | * @param integer $level 665 | * @return boolean 666 | */ 667 | public function hasAccessLevel($level) 668 | { 669 | if ($this->guest()) 670 | return false; 671 | 672 | return $this->user()->hasAccessLevel($level); 673 | } 674 | 675 | /** 676 | * Check if user has access to a route or routes. 677 | * 678 | * @param mixed $route 679 | * @param mixed $user 680 | * @return boolean 681 | */ 682 | public function hasRouteAccess($route, $user = null) 683 | { 684 | if (is_array($route)) // multiple routes are being checked; return true if any one of them is accessible 685 | { 686 | $routes = $route; 687 | foreach ($routes as $route) 688 | { 689 | if ($this->hasRouteAccess($route, $user)) 690 | { 691 | return true; 692 | } 693 | } 694 | } 695 | else // otherwise, check the individual route 696 | { 697 | $routes = config('auth_routes'); 698 | 699 | if (!is_array($routes)) 700 | $routes = []; 701 | 702 | if (is_null($user)) 703 | $user = $this->user(); 704 | 705 | if (is_string($route)) 706 | $routeName = $route; 707 | else 708 | $routeName = $this->getRouteName($route); 709 | 710 | $permissions = false; 711 | 712 | $routeAccessStatuses = []; 713 | if (!empty($user)) 714 | $routeAccessStatuses = $user->getRouteAccessStatuses(); 715 | 716 | // if the route access status has already been calculated, use pre-existing access status 717 | if (isset($routeAccessStatuses[$routeName])) 718 | return $routeAccessStatuses[$routeName]; 719 | 720 | if (array_key_exists($routeName, $routes)) 721 | { 722 | $permissions = $this->formatPermissionsArray($routes[$routeName]); 723 | } 724 | else 725 | { 726 | $routeNameArray = explode('.', $routeName); 727 | 728 | for ($r = (count($routeNameArray) - 2); $r >= 0; $r--) 729 | { 730 | if ($permissions === false) 731 | { 732 | $routeNamePartial = ""; 733 | 734 | for ($a = 0; $a <= $r; $a++) 735 | { 736 | if ($routeNamePartial != "") 737 | $routeNamePartial .= "."; 738 | 739 | $routeNamePartial .= $routeNameArray[$a]; 740 | } 741 | 742 | $routeNamePartial .= ".*"; 743 | 744 | if (array_key_exists($routeNamePartial, $routes)) 745 | { 746 | $routeName = $routeNamePartial; 747 | 748 | // if the route access status has already been calculated, use pre-existing access status 749 | if (isset($routeAccessStatuses[$routeName])) 750 | return $routeAccessStatuses[$routeName]; 751 | 752 | $permissions = $this->formatPermissionsArray($routes[$routeName]); 753 | } 754 | } 755 | } 756 | } 757 | 758 | $authorized = true; 759 | 760 | if ($permissions !== false) 761 | { 762 | if (is_null($permissions)) 763 | $permissions = []; 764 | 765 | // if user does not exist, check whether permissions array is empty 766 | if (empty($user)) 767 | { 768 | if (!empty($permissions)) 769 | $authorized = false; 770 | 771 | return $authorized; 772 | } 773 | 774 | $allPermissionsRequired = in_array('[ALL]', $permissions); 775 | 776 | if ($allPermissionsRequired) 777 | { 778 | foreach ($permissions as $p => $permission) 779 | { 780 | if ($permission == "[ALL]") 781 | unset($permissions[$p]); 782 | } 783 | 784 | $authorized = $this->hasPermissions($permissions); 785 | } 786 | else 787 | { 788 | $authorized = $this->hasPermission($permissions); 789 | } 790 | 791 | if (!$authorized) 792 | { 793 | Config::set('auth.unauthorized_route.name', $routeName); 794 | Config::set('auth.unauthorized_route.permissions', $permissions); 795 | Config::set('auth.unauthorized_route.all_permissions_required', $allPermissionsRequired); 796 | } 797 | } 798 | 799 | if (!empty($user)) 800 | $user->setRouteAccessStatus($routeName, $authorized); 801 | 802 | return $authorized; 803 | } 804 | } 805 | 806 | /** 807 | * Check if current user has access to a route by URL. 808 | * 809 | * @param string $url 810 | * @param string $verb 811 | * @param boolean $default 812 | * @param mixed $user 813 | * @return boolean 814 | */ 815 | public function hasAccess($url, $verb = 'get', $default = false, $user = null) 816 | { 817 | $route = $this->getRouteFromUrl($url, $verb); 818 | 819 | if (is_null($route)) 820 | return $default; 821 | 822 | if (is_null($user)) 823 | $user = $this->user(); 824 | 825 | return $this->hasRouteAccess($route); 826 | } 827 | 828 | /** 829 | * Get a route name from a route. If no route name is applied to the route, one will be created from the prefix, controller, and function. 830 | * 831 | * @param mixed $route 832 | * @return string 833 | */ 834 | public function getRouteName($route = null) 835 | { 836 | if (is_null($route)) 837 | $route = Route::current(); 838 | 839 | $routeAction = $route->getAction(); 840 | 841 | if (isset($routeAction['as'])) 842 | { 843 | $routeName = $routeAction['as']; 844 | } 845 | else // create route name from route data 846 | { 847 | $prefix = $routeAction['prefix']; 848 | 849 | if (!is_null($prefix)) 850 | { 851 | if (substr($prefix, 0, 1) == "/") 852 | $prefix = substr($prefix, 1); 853 | 854 | $routeName = str_replace('/', '.', $prefix); 855 | } 856 | else 857 | { 858 | $routeName = ""; 859 | } 860 | 861 | $uses = explode('@', $routeAction['uses']); 862 | $controller = explode('\\', $uses[0]); 863 | 864 | $controller = str_replace('_', '-', snake_case(str_replace('Controller', '', end($controller)))); 865 | 866 | if ($controller != substr($routeName, -strlen($controller))) 867 | { 868 | if ($routeName != "") 869 | $routeName .= "."; 870 | 871 | $routeName .= $controller; 872 | } 873 | 874 | if (count($uses) > 1) 875 | { 876 | $function = end($uses); 877 | 878 | if ($routeName != "") 879 | $routeName .= "."; 880 | 881 | $routeName .= str_replace('_', '-', snake_case($function)); 882 | } 883 | } 884 | 885 | return $routeName; 886 | } 887 | 888 | /** 889 | * Ensure that permissions are an array. 890 | * 891 | * @return array 892 | */ 893 | public function formatPermissionsArray($permissions) 894 | { 895 | if (is_string($permissions)) 896 | $permissions = [$permissions]; 897 | 898 | return $permissions; 899 | } 900 | 901 | /** 902 | * Get a route from a URL. 903 | * 904 | * @param string $url 905 | * @param string $verb 906 | * @return boolean 907 | */ 908 | public function getRouteFromUrl($url, $verb = 'get') 909 | { 910 | $router = new Router(new \Illuminate\Events\Dispatcher()); 911 | 912 | $router->setRoutes(Route::getRoutes()); 913 | 914 | return $router->resolveRouteFromUrl($url, $verb); 915 | } 916 | 917 | /** 918 | * Check a particular state for current user. 919 | * 920 | * @param string $name 921 | * @param mixed $state 922 | * @param mixed $default 923 | * @return boolean 924 | */ 925 | public function checkState($name, $state = true, $default = null) 926 | { 927 | if ($this->guest()) 928 | return false; 929 | 930 | return $this->user()->checkState($name, $state, $default); 931 | } 932 | 933 | /** 934 | * Get a particular state for current user. 935 | * 936 | * @param string $name 937 | * @param mixed $default 938 | * @return mixed 939 | */ 940 | public function getState($name, $default = null) 941 | { 942 | if ($this->guest()) 943 | return !is_null($default) ? $default : config('auth.state_defaults.'.snake_case($name)); 944 | 945 | return $this->user()->getState($name, $default); 946 | } 947 | 948 | /** 949 | * Set a particular name for current user. 950 | * 951 | * @param string $name 952 | * @param mixed $state 953 | * @return boolean 954 | */ 955 | public function setState($name, $state = true) 956 | { 957 | if ($this->guest()) 958 | return false; 959 | 960 | return $this->user()->setState($name, $state); 961 | } 962 | 963 | /** 964 | * Remove a particular name for current user. 965 | * 966 | * @param string $name 967 | * @param mixed $state 968 | * @return boolean 969 | */ 970 | public function removeState($name, $state = true) 971 | { 972 | if ($this->guest()) 973 | return false; 974 | 975 | return $this->user()->removeState($name, $state); 976 | } 977 | 978 | /** 979 | * Clear state data for current user. 980 | * 981 | * @return boolean 982 | */ 983 | public function clearStateData() 984 | { 985 | if ($this->guest()) 986 | return false; 987 | 988 | return $this->user()->clearStateData(); 989 | } 990 | 991 | /** 992 | * Create a new user account. 993 | * 994 | * @param mixed $input 995 | * @param boolean $autoActivate 996 | * @param boolean $sendEmail 997 | * @return User 998 | */ 999 | public function createUser($input = null, $autoActivate = false, $sendEmail = true) 1000 | { 1001 | return User::createAccount($input, $autoActivate, $sendEmail); 1002 | } 1003 | 1004 | /** 1005 | * Attempt to activate a user account by the user ID and activation code. 1006 | * 1007 | * @param integer $id 1008 | * @param string $activationCode 1009 | * @return boolean 1010 | */ 1011 | public function activate($id = 0, $activationCode = '') 1012 | { 1013 | $user = User::find($id); 1014 | 1015 | if (!empty($user) && !$user->isActivated() && ($this->is('admin') || $activationCode == $user->activation_code)) 1016 | { 1017 | $user->fill(['activated_at' => date('Y-m-d H:i:s')])->save(); 1018 | 1019 | return true; 1020 | } 1021 | 1022 | return false; 1023 | } 1024 | 1025 | /** 1026 | * Email the user based on a specified type. 1027 | * 1028 | * @param object $user 1029 | * @param string $type 1030 | * @return boolean 1031 | */ 1032 | public function sendEmail($user, $type) 1033 | { 1034 | $emailTypes = config('auth.email_types'); 1035 | 1036 | if (in_array($type, $emailTypes)) 1037 | { 1038 | $viewLocation = config('auth.views_location').config('auth.views_location_email').'.'; 1039 | 1040 | $subject = trans('identify::email_subjects.'.$type); 1041 | 1042 | if (config('auth.app_name_email_subject_prefix')) 1043 | $subject = config('app.name').': '.$subject; 1044 | 1045 | Mail::send($viewLocation.$type, ['user' => $user], function($mail) use ($user, $subject) 1046 | { 1047 | $mail 1048 | ->to($user->email, $user->getName()) 1049 | ->subject($subject); 1050 | }); 1051 | 1052 | return true; 1053 | } 1054 | 1055 | return false; 1056 | } 1057 | 1058 | } -------------------------------------------------------------------------------- /src/IdentifyServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 22 | __DIR__.'/config/auth.php' => config_path('auth.php'), 23 | __DIR__.'/config/auth_routes.php' => config_path('auth_routes.php'), 24 | __DIR__.'/resources/lang' => resource_path('lang/vendor/identify'), 25 | __DIR__.'/resources/views' => resource_path('views/vendor/identify'), 26 | ]); 27 | 28 | $this->publishes([ 29 | __DIR__.'/database/migrations' => database_path('migrations'), 30 | ], 'migrations'); 31 | 32 | $this->loadTranslationsFrom(__DIR__.'/resources/lang', 'identify'); 33 | 34 | $this->loadViewsFrom(__DIR__.'/resources/views', 'identify'); 35 | } 36 | 37 | /** 38 | * Register the service provider. 39 | * 40 | * @return void 41 | */ 42 | public function register() 43 | { 44 | \Auth::extend('session', function($app, $name, array $config) 45 | { 46 | $model = $app['config']['auth.providers.users.model']; 47 | 48 | $provider = new IdentifyUserProvider($app['hash'], $model); 49 | 50 | return new Identify($name, $provider, $this->app['session.store'], $this->app['request']); 51 | }); 52 | } 53 | 54 | /** 55 | * Get the services provided by the provider. 56 | * 57 | * @return array 58 | */ 59 | public function provides() 60 | { 61 | return ['Regulus\Identify\Identify']; 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /src/IdentifyUserProvider.php: -------------------------------------------------------------------------------- 1 | model = $model; 33 | $this->hasher = $hasher; 34 | } 35 | 36 | /** 37 | * Retrieve a user by their unique identifier. 38 | * 39 | * @param mixed $identifier 40 | * @return \Illuminate\Contracts\Auth\Authenticatable|null 41 | */ 42 | public function retrieveById($identifier) 43 | { 44 | return $this->createModel()->newQuery()->find($identifier); 45 | } 46 | 47 | /** 48 | * Retrieve a user by their unique identifier and "remember me" token. 49 | * 50 | * @param mixed $identifier 51 | * @param string $token 52 | * @return \Illuminate\Contracts\Auth\Authenticatable|null 53 | */ 54 | public function retrieveByToken($identifier, $token) 55 | { 56 | $model = $this->createModel(); 57 | 58 | return $model 59 | ->newQuery() 60 | ->where($model->getKeyName(), $identifier) 61 | ->where($model->getRememberTokenName(), $token) 62 | ->first(); 63 | } 64 | 65 | /** 66 | * Update the "remember me" token for the given user in storage. 67 | * 68 | * @param \Illuminate\Contracts\Auth\Authenticatable $user 69 | * @param string $token 70 | * @return void 71 | */ 72 | public function updateRememberToken(Authenticatable $user, $token) 73 | { 74 | $user->setRememberToken($token); 75 | 76 | $user->save(); 77 | } 78 | 79 | /** 80 | * Retrieve a user by the given credentials. 81 | * 82 | * @param array $credentials 83 | * @return \Illuminate\Contracts\Auth\Authenticatable|null 84 | */ 85 | public function retrieveByCredentials(array $credentials) 86 | { 87 | // First we will add each credential element to the query as a where clause. 88 | // Then we can execute the query and, if we found a user, return it in a 89 | // Eloquent User "model" that will be utilized by the Guard instances. 90 | $query = $this->createModel()->newQuery(); 91 | 92 | foreach ($credentials as $key => $value) 93 | { 94 | $value = trim($value); 95 | 96 | if ($key == "identifier") 97 | { 98 | $usernameField = config('auth.username.field'); 99 | $usernameAllowSpaces = config('auth.username.allow_spaces'); 100 | $logInByUsernameOrEmail = config('auth.log_in_username_or_email'); 101 | 102 | if (!$usernameAllowSpaces) 103 | $value = str_replace(' ', '', $value); 104 | 105 | if ($logInByUsernameOrEmail) 106 | $query->where(function($query) use ($usernameField, $value) 107 | { 108 | $query 109 | ->orWhere($usernameField, $value) 110 | ->orWhere('email', $value); 111 | }); 112 | else 113 | $query->where($usernameField, $value); 114 | 115 | } else { 116 | if (!str_contains($key, 'password')) 117 | $query->where($key, $value); 118 | } 119 | } 120 | 121 | return $query->first(); 122 | } 123 | 124 | /** 125 | * Validate a user against the given credentials. 126 | * 127 | * @param \Illuminate\Contracts\Auth\Authenticatable $user 128 | * @param array $credentials 129 | * @return bool 130 | */ 131 | public function validateCredentials(Authenticatable $user, array $credentials) 132 | { 133 | $plain = $credentials['password']; 134 | 135 | return $this->hasher->check($plain, $user->getAuthPassword()); 136 | } 137 | 138 | /** 139 | * Create a new instance of the model. 140 | * 141 | * @return \Illuminate\Database\Eloquent\Model 142 | */ 143 | public function createModel() 144 | { 145 | $class = '\\'.ltrim($this->model, '\\'); 146 | 147 | return new $class; 148 | } 149 | 150 | } -------------------------------------------------------------------------------- /src/Libraries/Router.php: -------------------------------------------------------------------------------- 1 | findRoute($request); 21 | } 22 | catch (\Exception $e) // prevent exception from breaking app when checking access permissions 23 | { 24 | return null; 25 | } 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /src/Middleware/AuthenticateByToken.php: -------------------------------------------------------------------------------- 1 | header('api-token'); 20 | 21 | if (is_null($token)) 22 | $token = $request->get('api_token'); 23 | 24 | if (!Auth::check() && !is_null($token) && $token != "") 25 | { 26 | $token = explode(':', $token); 27 | 28 | if (count($token) == 2) 29 | { 30 | $user = Auth::getProvider()->createModel()->find($token[0]); 31 | 32 | if ($user && $user->checkApiToken($token[1])) 33 | { 34 | Auth::login($user, false, true); 35 | } 36 | } 37 | } 38 | 39 | return $next($request); 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /src/Middleware/Authorize.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 26 | } 27 | 28 | /** 29 | * Handle an incoming request. 30 | * 31 | * @param \Illuminate\Http\Request $request 32 | * @param \Closure $next 33 | * @return mixed 34 | */ 35 | public function handle($request, Closure $next) 36 | { 37 | $authorized = $this->auth->hasRouteAccess($request->route()); 38 | 39 | if (!$authorized) 40 | { 41 | if ($request->ajax() || $request->wantsJson()) 42 | { 43 | return response(trans('identify::messages.unauthorized_api'), 403); 44 | } 45 | else 46 | { 47 | if (config('auth.unauthorized_redirect')) 48 | return Redirect::route(config('auth.unauthorized_redirect_route'))->with('messages', [ 49 | 'error' => trans('identify::messages.unauthorized'), 50 | ]); 51 | 52 | abort(config('auth.unauthorized_error_code')); 53 | } 54 | } 55 | 56 | return $next($request); 57 | } 58 | 59 | } -------------------------------------------------------------------------------- /src/Models/ApiToken.php: -------------------------------------------------------------------------------- 1 | table = Auth::getTableName($this->table); 33 | } 34 | 35 | /** 36 | * The user that the state belongs to. 37 | * 38 | * @return User 39 | */ 40 | public function user() 41 | { 42 | return $this->belongsTo(config('auth.model')); 43 | } 44 | 45 | /** 46 | * Filter out expired API tokens. 47 | * 48 | * @return \Illuminate\Database\Eloquent\Builder 49 | */ 50 | public function scopeOnlyActive($query) 51 | { 52 | return $query->where(function($query) 53 | { 54 | $query 55 | ->whereNull('expired_at') 56 | ->orWhere('expired_at', '>', date('Y-m-d H:i:s')); 57 | }); 58 | } 59 | 60 | /** 61 | * Filter out active API tokens. 62 | * 63 | * @return \Illuminate\Database\Eloquent\Builder 64 | */ 65 | public function scopeOnlyExpired($query) 66 | { 67 | return $query->where(function($query) 68 | { 69 | $query 70 | ->whereNotNull('expired_at') 71 | ->orWhere('expired_at', '<=', date('Y-m-d H:i:s')); 72 | }); 73 | } 74 | 75 | /** 76 | * Filter out expired API tokens. 77 | * 78 | * @param boolean $token 79 | * @return boolean 80 | */ 81 | public function check($token) 82 | { 83 | return Hash::check($token, $this->token); 84 | } 85 | 86 | /** 87 | * Reset the API token. 88 | * 89 | * @return string 90 | */ 91 | public function reset() 92 | { 93 | $token = Auth::makeNewApiToken(); 94 | 95 | $this->update(['token' => Hash::make($token)]); 96 | 97 | return $token; 98 | } 99 | 100 | } -------------------------------------------------------------------------------- /src/Models/CachedPermissionsRecord.php: -------------------------------------------------------------------------------- 1 | 'json', 30 | ]; 31 | 32 | /** 33 | * The constructor which adds the table prefix from the config settings. 34 | * 35 | */ 36 | public function __construct(array $attributes = []) 37 | { 38 | parent::__construct($attributes); 39 | 40 | $this->table = Auth::getTableName($this->table); 41 | } 42 | 43 | /** 44 | * The user that the state belongs to. 45 | * 46 | * @return User 47 | */ 48 | public function user() 49 | { 50 | return $this->belongsTo(config('auth.model')); 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /src/Models/Permission.php: -------------------------------------------------------------------------------- 1 | table = Auth::getTableName($this->table); 43 | } 44 | 45 | /** 46 | * The users that have the permission. 47 | * 48 | * @return Collection 49 | */ 50 | public function users() 51 | { 52 | return $this->belongsToMany(config('auth.model'), Auth::getTableName('user_permissions')) 53 | ->orderBy('username'); 54 | } 55 | 56 | /** 57 | * The roles that have the permission. 58 | * 59 | * @return Collection 60 | */ 61 | public function roles() 62 | { 63 | return $this->belongsToMany('Regulus\Identify\Models\Role', Auth::getTableName('role_permissions')) 64 | ->orderBy('name'); 65 | } 66 | 67 | /** 68 | * The parent permission that the permission belongs to. 69 | * 70 | * @return Permission 71 | */ 72 | public function parentPermission() 73 | { 74 | return $this->belongsTo('Regulus\Identify\Models\Permission', 'parent_id'); 75 | } 76 | 77 | /** 78 | * The sub permissions of the permission. 79 | * 80 | * @return Collection 81 | */ 82 | public function subPermissions() 83 | { 84 | return $this->hasMany('Regulus\Identify\Models\Permission', 'parent_id'); 85 | } 86 | 87 | /** 88 | * Get a select box list of permissions. 89 | * 90 | * @param mixed $select 91 | * @return array 92 | */ 93 | public static function getSelectable($select = null) 94 | { 95 | if (is_null($select) || !is_array($select) || count($select) == 0) 96 | $select = ['id', 'name']; 97 | 98 | if (count($select) == 1) 99 | $select[1] = $select[0]; 100 | 101 | $permissions = static::orderBy('name')->get(); 102 | $options = []; 103 | 104 | foreach ($permissions as $permission) { 105 | $options[$permission->{$select[0]}] = $permission->{$select[1]}; 106 | } 107 | 108 | return $options; 109 | } 110 | 111 | } -------------------------------------------------------------------------------- /src/Models/Role.php: -------------------------------------------------------------------------------- 1 | 'boolean', 41 | ]; 42 | 43 | /** 44 | * The permissions array for the role. 45 | * 46 | * @var array 47 | */ 48 | public $permissions = []; 49 | 50 | /** 51 | * The constructor which adds the table prefix from the config settings. 52 | * 53 | */ 54 | public function __construct(array $attributes = []) 55 | { 56 | parent::__construct($attributes); 57 | 58 | $this->table = Auth::getTableName($this->table); 59 | } 60 | 61 | /** 62 | * The users of the role. 63 | * 64 | * @return Collection 65 | */ 66 | public function users() 67 | { 68 | return $this->belongsToMany(config('auth.model'), Auth::getTableName('user_roles')) 69 | ->orderBy('username'); 70 | } 71 | 72 | /** 73 | * The permissions of the role. 74 | * 75 | * @return Collection 76 | */ 77 | public function rolePermissions() 78 | { 79 | return $this->belongsToMany('Regulus\Identify\Models\Permission', Auth::getTableName('role_permissions')) 80 | ->withTimestamps() 81 | ->orderBy('display_order') 82 | ->orderBy('name'); 83 | } 84 | 85 | /** 86 | * Get a select box list of roles. 87 | * 88 | * @param mixed $select 89 | * @return array 90 | */ 91 | public static function getSelectable($select = null) 92 | { 93 | if (is_null($select) || !is_array($select) || count($select) == 0) 94 | $select = ['role', 'name']; 95 | 96 | if (count($select) == 1) 97 | $select[1] = $select[0]; 98 | 99 | $roles = static::orderBy('display_order')->get(); 100 | $options = []; 101 | 102 | foreach ($roles as $role) { 103 | $options[$role->{$select[0]}] = $role->{$select[1]}; 104 | } 105 | 106 | return $options; 107 | } 108 | 109 | /** 110 | * Get the permissions of the role. 111 | * 112 | * @param string $field 113 | * @return array 114 | */ 115 | public function getPermissions($field = 'permission') 116 | { 117 | if (empty($this->permissions)) 118 | { 119 | $this->permissions = []; 120 | 121 | // get role derived permissions 122 | foreach ($this->rolePermissions as $permission) 123 | { 124 | if (!in_array($permission->{$field}, $this->permissions)) 125 | $this->permissions[] = $permission->{$field}; 126 | } 127 | 128 | // get access level derived permissions 129 | if (config('auth.enable_access_level')) 130 | { 131 | $permissions = Permission::where('access_level', '<=', $this->access_level)->get(); 132 | foreach ($permissions as $permission) 133 | { 134 | if (!in_array($permission->{$field}, $this->permissions)) 135 | $this->permissions[] = $permission->{$field}; 136 | } 137 | } 138 | 139 | asort($this->permissions); 140 | } 141 | 142 | return $this->permissions; 143 | } 144 | 145 | /** 146 | * Get the permission names of the role. 147 | * 148 | * @return array 149 | */ 150 | public function getPermissionNames() 151 | { 152 | return $this->getPermissions('name'); 153 | } 154 | 155 | /** 156 | * Check if a role has a particular permission. 157 | * 158 | * @param mixed $permissions 159 | * @return boolean 160 | */ 161 | public function hasPermission($permissions) 162 | { 163 | $permissions = Auth::formatPermissionsArray($permissions); 164 | 165 | if (empty($permissions)) 166 | return true; 167 | 168 | foreach ($permissions as $permission) 169 | { 170 | if (in_array($permission, $this->getPermissions())) 171 | return true; 172 | } 173 | 174 | return false; 175 | } 176 | 177 | /** 178 | * Add a permission to the role. 179 | * 180 | * @return boolean 181 | */ 182 | public function addPermission($permission) 183 | { 184 | if (!$this->hasDirectPermission($permission)) 185 | { 186 | $permissionRecord = null; 187 | 188 | if (is_integer($permission)) 189 | $permissionRecord = Permission::find($permission); 190 | 191 | if (is_string($permission)) 192 | $permissionRecord = Permission::where('permission', $permission)->first(); 193 | 194 | if (!empty($permissionRecord)) 195 | { 196 | $this->rolePermissions()->attach($permissionRecord->id); 197 | 198 | return true; 199 | } 200 | } 201 | 202 | return false; 203 | } 204 | 205 | /** 206 | * Remove a permission from the role. 207 | * 208 | * @return boolean 209 | */ 210 | public function removePermission($permission) 211 | { 212 | if ($this->hasDirectPermission($permission)) 213 | { 214 | $permissionRecord = null; 215 | 216 | if (is_integer($permission)) 217 | $permissionRecord = Permission::find($permission); 218 | 219 | if (is_string($permission)) 220 | $permissionRecord = Permission::where('permission', $permission)->first(); 221 | 222 | if (!empty($permissionRecord)) 223 | { 224 | $this->rolePermissions()->detach($permissionRecord->id); 225 | 226 | return true; 227 | } 228 | } 229 | 230 | return false; 231 | } 232 | 233 | /** 234 | * Check if a permission has been directly applied to the role. 235 | * 236 | * @param mixed $permission 237 | * @return boolean 238 | */ 239 | public function hasDirectPermission($permission) 240 | { 241 | foreach ($this->rolePermissions as $permissionListed) 242 | { 243 | if (is_integer($permission) && $permissionListed->id == $permission) 244 | return true; 245 | 246 | if (is_string($permission) && $permissionListed->permission == $permission) 247 | return true; 248 | } 249 | 250 | return false; 251 | } 252 | 253 | } -------------------------------------------------------------------------------- /src/Models/StateItem.php: -------------------------------------------------------------------------------- 1 | 'json', 30 | ]; 31 | 32 | /** 33 | * The constructor which adds the table prefix from the config settings. 34 | * 35 | */ 36 | public function __construct(array $attributes = []) 37 | { 38 | parent::__construct($attributes); 39 | 40 | $this->table = Auth::getTableName($this->table); 41 | } 42 | 43 | /** 44 | * The user that the state belongs to. 45 | * 46 | * @return User 47 | */ 48 | public function user() 49 | { 50 | return $this->belongsTo(config('auth.model')); 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /src/Models/User.php: -------------------------------------------------------------------------------- 1 | fillable) <= 3) // allow extended User model to override "fillable" directly rather than via config 119 | $this->fillable = config('auth.fillable_fields'); 120 | 121 | parent::__construct($attributes); 122 | 123 | $this->table = Auth::getTableName($this->table); 124 | } 125 | 126 | /** 127 | * The roles of the user. 128 | * 129 | * @return Collection 130 | */ 131 | public function roles() 132 | { 133 | return $this->belongsToMany('Regulus\Identify\Models\Role', Auth::getTableName('user_roles')) 134 | ->withTimestamps() 135 | ->orderBy('display_order') 136 | ->orderBy('name'); 137 | } 138 | 139 | /** 140 | * The permissions of the user. 141 | * 142 | * @return Collection 143 | */ 144 | public function userPermissions() 145 | { 146 | return $this->belongsToMany('Regulus\Identify\Models\Permission', Auth::getTableName('user_permissions')) 147 | ->withTimestamps() 148 | ->orderBy('display_order') 149 | ->orderBy('name'); 150 | } 151 | 152 | /** 153 | * The state that belongs to the user. 154 | * 155 | * @return StateItem 156 | */ 157 | public function stateItem() 158 | { 159 | return $this->hasOne('Regulus\Identify\Models\StateItem'); 160 | } 161 | 162 | /** 163 | * The state that belongs to the user. 164 | * 165 | * @return CachedPermissionsRecord 166 | */ 167 | public function cachedPermissionsRecord() 168 | { 169 | return $this->hasOne('Regulus\Identify\Models\CachedPermissionsRecord'); 170 | } 171 | 172 | /** 173 | * The API tokens that belongs to the user. 174 | * 175 | * @return Collection 176 | */ 177 | public function apiTokens() 178 | { 179 | return $this->hasMany('Regulus\Identify\Models\ApiToken'); 180 | } 181 | 182 | /** 183 | * Allow user to be used in polymorphic relationships. 184 | * 185 | * @return Collection 186 | */ 187 | public function content() 188 | { 189 | return $this->morphTo(); 190 | } 191 | 192 | /** 193 | * Filter out users that do not have a role or roles. 194 | * 195 | * @param mixed $roles 196 | * @param boolean $joinRoles 197 | * @return \Illuminate\Database\Eloquent\Builder 198 | */ 199 | public function scopeOnlyRoles($query, $roles, $joinRoles = true) 200 | { 201 | if (is_string($roles)) 202 | $roles = [$roles]; 203 | 204 | if ($joinRoles) 205 | $query = $this->scopeJoinRoles($query); 206 | 207 | return $query->whereIn('auth_roles.role', $roles); 208 | } 209 | 210 | /** 211 | * Filter out users that have a role or roles. 212 | * 213 | * @param mixed $roles 214 | * @param boolean $joinRoles 215 | * @return \Illuminate\Database\Eloquent\Builder 216 | */ 217 | public function scopeExceptRoles($query, $roles, $joinRoles = true) 218 | { 219 | if (is_string($roles)) 220 | $roles = [$roles]; 221 | 222 | if ($joinRoles) 223 | $query = $this->scopeJoinRoles($query); 224 | 225 | return $query->whereNotIn('auth_roles.role', $roles); 226 | } 227 | 228 | /** 229 | * Join the roles for use with other scopes. 230 | * 231 | * @return \Illuminate\Database\Eloquent\Builder 232 | */ 233 | public function scopeJoinRoles($query) 234 | { 235 | return $query 236 | ->select('auth_users.*') 237 | ->leftJoin('auth_user_roles', 'auth_user_roles.user_id', '=', 'auth_users.id') 238 | ->join('auth_roles', 'auth_roles.id', '=', 'auth_user_roles.role_id') 239 | ->groupBy('auth_users.id'); 240 | } 241 | 242 | /** 243 | * Get the unique identifier for the user. 244 | * 245 | * @return mixed 246 | */ 247 | public function getAuthIdentifier() 248 | { 249 | return $this->getKey(); 250 | } 251 | 252 | /** 253 | * Get the password for the user. 254 | * 255 | * @return string 256 | */ 257 | public function getAuthPassword() 258 | { 259 | return $this->password; 260 | } 261 | 262 | /** 263 | * Get the e-mail address where password reminders are sent. 264 | * 265 | * @return string 266 | */ 267 | public function getReminderEmail() 268 | { 269 | return $this->email; 270 | } 271 | 272 | /** 273 | * Check whether user's account is active (activated and not banned). 274 | * 275 | * @return boolean 276 | */ 277 | public function isActive() 278 | { 279 | return $this->isActivated() && !$this->isBanned(); 280 | } 281 | 282 | /** 283 | * Check whether user's account is activated. 284 | * 285 | * @return boolean 286 | */ 287 | public function isActivated() 288 | { 289 | return !is_null($this->activated_at); 290 | } 291 | 292 | /** 293 | * Check whether user's account is banned. 294 | * 295 | * @return boolean 296 | */ 297 | public function isBanned() 298 | { 299 | return !is_null($this->banned_at); 300 | } 301 | 302 | /** 303 | * Get the reason a user was banned. 304 | * 305 | * @return string 306 | */ 307 | public function getBanReason() 308 | { 309 | if (!$this->isBanned()) 310 | return null; 311 | 312 | return $this->ban_reason; 313 | } 314 | 315 | /** 316 | * Get the picture for the user. 317 | * 318 | * @param boolean $thumbnail 319 | * @return string 320 | */ 321 | public function getPicture($thumbnail = false) 322 | { 323 | $picture = URL::asset('assets/images/display-pic-default.png'); 324 | 325 | if (!$thumbnail) 326 | $file = config('auth.path_picture').config('auth.filename_picture'); 327 | else 328 | $file = config('auth.path_picture_thumbnail').config('auth.filename_picture_thumbnail'); 329 | 330 | $file = str_replace(':userId', $this->id, $file); 331 | 332 | if (is_file($file)) 333 | $picture = URL::to($file); 334 | 335 | return $picture; 336 | } 337 | 338 | /** 339 | * Get the name of the user. 340 | * 341 | * @return string 342 | */ 343 | public function getName($format = 'F L') 344 | { 345 | $name = str_replace('F', '{first}', $format); 346 | $name = str_replace('L', '{last}', $name); 347 | $name = str_replace('U', '{user}', $name); 348 | 349 | $name = str_replace('{first}', $this->first_name, $name); 350 | $name = str_replace('{last}', $this->last_name, $name); 351 | $name = str_replace('{user}', $this->{config('auth.username.field')}, $name); 352 | 353 | return trim($name); 354 | } 355 | 356 | /** 357 | * Get the account activation URL for the user. 358 | * 359 | * @return string 360 | */ 361 | public function getActivationUrl() 362 | { 363 | return url('account/activate/'.$this->id.'/'.$this->activation_token); 364 | } 365 | 366 | /** 367 | * Get the password reset email for a token. 368 | * 369 | * @param mixed $token 370 | * @return string 371 | */ 372 | public function getPasswordResetUrl($token = null) 373 | { 374 | if (is_null($token)) 375 | { 376 | $resetRequest = DB::table('password_resets')->where('email', $this->email)->orderBy('created_at', 'desc')->first(); 377 | 378 | if ($resetRequest) 379 | $token = $resetRequest->token; 380 | } 381 | 382 | return url('password/reset', $token).'?email='.urlencode($this->email); 383 | } 384 | 385 | /** 386 | * Reset the user's API token. 387 | * 388 | * @param mixed $tokenLifetime 389 | * @param boolean $returnTokenOnly 390 | * @return string 391 | */ 392 | public function resetApiToken($tokenLifetime = true, $returnTokenOnly = false) 393 | { 394 | $token = Auth::makeNewApiToken(); 395 | 396 | $max = config('auth.api_tokens.max'); 397 | 398 | $mobile = preg_match('/(android|phone|ipad|tablet)/i', request()->userAgent()); 399 | 400 | if ($tokenLifetime === true) 401 | { 402 | $tokenLifetime = config('auth.api_tokens.lifetime'.($mobile ? '_mobile' : '')); 403 | 404 | if ($mobile && $tokenLifetime === false) 405 | { 406 | $tokenLifetime = config('auth.api_tokens.lifetime'); 407 | } 408 | } 409 | 410 | $expiredAt = !is_null($tokenLifetime) && is_integer($tokenLifetime) ? date('Y-m-d H:i:s', time() + ($tokenLifetime * 60)) : null; 411 | 412 | if ($max > 1) // if max tokens is greater than 1, use relationship (otherwise just use "api_token" column) 413 | { 414 | $this->apiTokens()->onlyExpired()->delete(); // delete expired tokens 415 | 416 | $tokenData = [ 417 | 'token' => Hash::make($token), 418 | 'expired_at' => $expiredAt, 419 | ]; 420 | 421 | if ($this->apiTokens()->count() >= $max) 422 | { 423 | $apiToken = $this->apiTokens()->orderBy('updated_at', 'id')->first(); 424 | 425 | $apiToken->update($tokenData); 426 | } 427 | else 428 | { 429 | $this->apiTokens()->save(new ApiToken($tokenData)); 430 | } 431 | } 432 | else 433 | { 434 | $this->update([ 435 | 'api_token' => Hash::make($token), 436 | 'api_token_expired_at' => $expiredAt, 437 | ]); 438 | } 439 | 440 | if (!$returnTokenOnly) 441 | $token =$this->id.':'.$token; 442 | 443 | return $token; 444 | } 445 | 446 | /** 447 | * Attempt to activate a user account by the user ID and activation token. 448 | * 449 | * @param integer $id 450 | * @param string $activationToken 451 | * @return boolean 452 | */ 453 | public static function activate($id, $activationToken = '') 454 | { 455 | $user = User::find($id); 456 | 457 | if (!empty($user) && !$user->activated && (static::is('admin') || $activationToken == $user->activation_token)) 458 | { 459 | $user->activated_at = date('Y-m-d H:i:s'); 460 | $user->save(); 461 | 462 | return true; 463 | } 464 | 465 | return false; 466 | } 467 | 468 | /** 469 | * Create a new user account. 470 | * 471 | * @param mixed $input 472 | * @param boolean $autoActivate 473 | * @param boolean $sendEmail 474 | * @return User 475 | */ 476 | public static function createAccount($input = null, $autoActivate = false, $sendEmail = true) 477 | { 478 | //get input values 479 | if (is_null($input)) 480 | $input = Input::except('id'); 481 | 482 | // format name, username, and email address 483 | if (isset($input['first_name'])) 484 | $input['first_name'] = ucfirst(trim($input['first_name'])); 485 | 486 | if (isset($input['last_name'])) 487 | $input['last_name'] = ucfirst(trim($input['last_name'])); 488 | 489 | if (isset($input['name'])) 490 | $input['name'] = ucfirst(trim($input['name'])); 491 | 492 | if (isset($input['email'])) 493 | $input['email'] = trim($input['email']); 494 | 495 | if (!isset($input['first_name']) && !isset($input['last_name'])) 496 | $input['first_name'] = $input['name']; 497 | 498 | $input['password'] = Hash::make($input['password']); 499 | 500 | // set activated timestamp or activation token 501 | if ($autoActivate) 502 | $input['activated_at'] = date('Y-m-d H:i:s'); 503 | else 504 | $input['activation_token'] = str_random(32); 505 | 506 | // create user 507 | $user = static::create($input); 508 | 509 | // add user role(s) 510 | $roles = []; 511 | if (isset($input['roles']) && is_array($input['roles'])) 512 | { 513 | $roles = $input['roles']; 514 | } 515 | else 516 | { 517 | $roleId = Auth::is('admin') && isset($input['role_id']) ? $input['role_id'] : null; 518 | $role = Role::find($roleId); 519 | 520 | if (empty($role) || is_null($roleId)) 521 | { 522 | $role = Role::where('default', true)->orderBy('id')->first(); 523 | 524 | if (!empty($role)) 525 | $roleId = $role->id; 526 | } 527 | 528 | if (!is_null($roleId)) 529 | $roles = [$roleId]; 530 | } 531 | 532 | $user->roles()->sync($roles); 533 | 534 | // add user permission(s) 535 | $permissions = []; 536 | if (isset($input['permissions']) && is_array($input['permissions'])) 537 | { 538 | $permissions = $input['permissions']; 539 | } 540 | 541 | $user->userPermissions()->sync($permissions); 542 | 543 | // send account activation email to user 544 | if ($sendEmail) 545 | Auth::sendEmail($user, 'confirmation'); 546 | 547 | return $user; 548 | } 549 | 550 | /** 551 | * Get an active user by ID. 552 | * 553 | * @param integer $id 554 | * @return object 555 | */ 556 | public static function findActiveById($id) 557 | { 558 | return static::orderBy('id') 559 | ->where('id', $id) 560 | ->whereNotNull('activated_at') 561 | ->whereNull('banned_at') 562 | ->whereNull('deleted_at') 563 | ->first(); 564 | } 565 | 566 | /** 567 | * Get a user by their username or email address. 568 | * 569 | * @param string $identifier 570 | * @return boolean 571 | */ 572 | public static function findByUsernameOrEmail($identifier = '') 573 | { 574 | $identifier = trim(strtolower($identifier)); 575 | 576 | return User::where(function($query) use ($identifier) 577 | { 578 | $query 579 | ->where(DB::raw('lower('.config('auth.username.field').')'), $identifier) 580 | ->orWhere(DB::raw('lower(email)'), $identifier); 581 | })->first(); 582 | } 583 | 584 | /** 585 | * Get the username, which could be called "username" or "name" and is specified in the auth config file. 586 | * 587 | * @return \Illuminate\Database\Eloquent\Model 588 | */ 589 | public function getUsername() 590 | { 591 | return $this->{config('auth.username.field')}; 592 | } 593 | 594 | /** 595 | * Get the remember token. 596 | * 597 | * @return string 598 | */ 599 | public function getRememberToken() 600 | { 601 | return $this->remember_token; 602 | } 603 | 604 | /** 605 | * Get the remember token. 606 | * 607 | * @return void 608 | */ 609 | public function setRememberToken($value) 610 | { 611 | $this->remember_token = $value; 612 | } 613 | 614 | /** 615 | * Get the name of the remember token field. 616 | * 617 | * @return string 618 | */ 619 | public function getRememberTokenName() 620 | { 621 | return 'remember_token'; 622 | } 623 | 624 | /** 625 | * Get the highest access level assigned to the user, either directly or via the user's roles. 626 | * 627 | * @return integer 628 | */ 629 | public function getAccessLevel() 630 | { 631 | if (!is_null($this->accessLevel)) 632 | return $this->accessLevel; 633 | 634 | $this->accessLevel = 0; 635 | 636 | if ($this->access_level > $this->accessLevel) 637 | $this->accessLevel = $this->access_level; 638 | 639 | foreach ($this->roles as $role) 640 | { 641 | if ($role->access_level > $this->accessLevel) 642 | $this->accessLevel = $role->access_level; 643 | } 644 | 645 | return $this->accessLevel; 646 | } 647 | 648 | /** 649 | * Get the permissions of the user. 650 | * 651 | * @param boolean $ignoreCached 652 | * @param string $field 653 | * @param boolean $returnSources 654 | * @return array 655 | */ 656 | public function getPermissions($ignoreCached = false, $field = 'permission', $returnSources = false) 657 | { 658 | if (empty($this->permissions) || ($returnSources && empty($this->permissionSources))) 659 | { 660 | if (!$ignoreCached && $this->cachedPermissionsRecord) 661 | { 662 | if (!is_null($this->cachedPermissionsRecord->permissions)) 663 | $this->permissions = $this->cachedPermissionsRecord->permissions; 664 | } 665 | else 666 | { 667 | // get user derived permissions 668 | foreach ($this->userPermissions as $permission) 669 | { 670 | if (!in_array($permission->{$field}, $this->permissions)) 671 | { 672 | $this->permissions[] = $permission->{$field}; 673 | } 674 | 675 | $this->permissionSources[$permission->permission] = "User"; 676 | 677 | $this->addSubPermissionsToArray($permission, $field); 678 | } 679 | 680 | // get role derived permissions 681 | foreach ($this->roles as $role) 682 | { 683 | foreach ($role->rolePermissions as $permission) 684 | { 685 | if (!in_array($permission->{$field}, $this->permissions)) 686 | { 687 | $this->permissions[] = $permission->{$field}; 688 | } 689 | 690 | if (!isset($this->permissionSources[$permission->permission])) 691 | { 692 | $this->permissionSources[$permission->permission] = "Role:".$role->role.":".$role->name; 693 | } 694 | 695 | $this->addSubPermissionsToArray($permission, $field); 696 | } 697 | } 698 | 699 | // get access level derived permissions 700 | if (config('auth.enable_access_level')) 701 | { 702 | $permissions = Permission::where('access_level', '<=', $this->getAccessLevel())->get(); 703 | foreach ($permissions as $permission) 704 | { 705 | if (!in_array($permission->{$field}, $this->permissions)) 706 | { 707 | $this->permissions[] = $permission->{$field}; 708 | } 709 | 710 | if (!isset($this->permissionSources[$permission->permission])) 711 | { 712 | $this->permissionSources[$permission->permission] = "Access Level"; 713 | } 714 | 715 | $this->addSubPermissionsToArray($permission, $field); 716 | } 717 | } 718 | 719 | asort($this->permissions); 720 | } 721 | } 722 | 723 | if ($returnSources) 724 | return $this->permissionSources; 725 | 726 | return $this->permissions; 727 | } 728 | 729 | /** 730 | * Get the permission names of the user. 731 | * 732 | * @return array 733 | */ 734 | public function getPermissionNames() 735 | { 736 | return $this->getPermissions(true, 'name'); 737 | } 738 | 739 | /** 740 | * Get the permission sources of the user. 741 | * 742 | * @return array 743 | */ 744 | public function getPermissionSources() 745 | { 746 | return $this->getPermissions(empty($this->permissionSources), 'permission', true); 747 | } 748 | 749 | /** 750 | * Add the sub permissions of a permission to the permissions array. 751 | * 752 | * @param object $permission 753 | * @param string $field 754 | * @return void 755 | */ 756 | private function addSubPermissionsToArray($permission, $field) 757 | { 758 | foreach ($permission->subPermissions as $subPermission) 759 | { 760 | if (!in_array($subPermission->{$field}, $this->permissions)) 761 | { 762 | $this->permissions[] = $subPermission->{$field}; 763 | 764 | $this->addSubPermissionsToArray($subPermission, $field); 765 | } 766 | 767 | if (!isset($this->permissionSources[$subPermission->permission])) 768 | $this->permissionSources[$subPermission->permission] = "Permission:".$permission->permission.":".$permission->name; 769 | } 770 | } 771 | 772 | /** 773 | * Check if a user has a particular permission. 774 | * 775 | * @param mixed $permissions 776 | * @return boolean 777 | */ 778 | public function hasPermission($permissions) 779 | { 780 | $permissions = Auth::formatPermissionsArray($permissions); 781 | 782 | if (empty($permissions)) 783 | return true; 784 | 785 | foreach ($permissions as $permission) 786 | { 787 | if (in_array($permission, $this->getPermissions())) 788 | return true; 789 | } 790 | 791 | return false; 792 | } 793 | 794 | /** 795 | * Check if a user has a set of specified permissions. 796 | * 797 | * @param mixed $permissions 798 | * @return boolean 799 | */ 800 | public function hasPermissions($permissions) 801 | { 802 | $permissions = Auth::formatPermissionsArray($permissions); 803 | 804 | foreach ($permissions as $permission) 805 | { 806 | if (!in_array($permission, $this->getPermissions())) 807 | return false; 808 | } 809 | 810 | return true; 811 | } 812 | 813 | /** 814 | * An alias for hasPermission(). 815 | * 816 | * @param mixed $permissions 817 | * @return boolean 818 | */ 819 | public function can($permissions) 820 | { 821 | return $this->hasPermission($permissions); 822 | } 823 | 824 | /** 825 | * Get the source of a permission for a user. 826 | * 827 | * @param string $permission 828 | * @param boolean $includeRecordInfo 829 | * @return mixed 830 | */ 831 | public function getPermissionSource($permission, $includeRecordInfo = false) 832 | { 833 | $permissionSources = $this->getPermissionSources(); 834 | 835 | $type = null; 836 | $item = null; 837 | $name = null; 838 | 839 | if (array_key_exists($permission, $permissionSources)) 840 | { 841 | $permissionSource = explode(':', $permissionSources[$permission]); 842 | 843 | $type = isset($permissionSource[0]) ? $permissionSource[0] : null; 844 | 845 | if (!$includeRecordInfo) 846 | return $type; 847 | 848 | $item = isset($permissionSource[1]) ? $permissionSource[1] : null; 849 | $name = isset($permissionSource[2]) ? $permissionSource[2] : null; 850 | } 851 | 852 | if ($includeRecordInfo) 853 | return (object) [ 854 | 'type' => $type, 855 | 'item' => $item, 856 | 'name' => $name, 857 | ]; 858 | 859 | return $type; 860 | } 861 | 862 | /** 863 | * Cache permissions to reduce number of necessary permissions-related database queries per request. 864 | * 865 | * @return void 866 | */ 867 | public function cachePermissions() 868 | { 869 | $this->userPermissions = $this->userPermissions()->get(); // refresh directly applied permissions 870 | $this->roles = $this->roles()->get(); // refresh roles 871 | 872 | $this->permissions = []; // clear permissions array in case it has already been populated 873 | 874 | $permissions = $this->getPermissions(true); // get permissions array and ignore currently cached permissions set 875 | 876 | if (!empty($permissions)) 877 | $permissions = array_values($permissions); 878 | else 879 | $permissions = null; 880 | 881 | $data = ['permissions' => $permissions]; 882 | 883 | if ($this->cachedPermissionsRecord) 884 | $this->cachedPermissionsRecord->update($data); 885 | else 886 | $this->cachedPermissionsRecord()->save(new CachedPermissionsRecord)->update($data); 887 | } 888 | 889 | /** 890 | * Add a permission to the user. 891 | * 892 | * @param mixed $permission 893 | * @param boolean $cache 894 | * @return boolean 895 | */ 896 | public function addPermission($permission, $cache = true) 897 | { 898 | if (!$this->hasDirectPermission($permission)) 899 | { 900 | $permissionRecord = null; 901 | 902 | if (is_integer($permission)) 903 | $permissionRecord = Permission::find($permission); 904 | 905 | if (is_string($permission)) 906 | $permissionRecord = Permission::where('permission', $permission)->first(); 907 | 908 | if (!empty($permissionRecord)) 909 | { 910 | $this->userPermissions()->attach($permissionRecord->id); 911 | 912 | if ($cache) 913 | $this->cachePermissions(); 914 | 915 | return true; 916 | } 917 | } 918 | 919 | return false; 920 | } 921 | 922 | /** 923 | * Remove a permission from the user. 924 | * 925 | * @param mixed $permission 926 | * @param boolean $cache 927 | * @return boolean 928 | */ 929 | public function removePermission($permission, $cache = true) 930 | { 931 | if ($this->hasDirectPermission($permission)) 932 | { 933 | $permissionRecord = null; 934 | 935 | if (is_integer($permission)) 936 | $permissionRecord = Permission::find($permission); 937 | 938 | if (is_string($permission)) 939 | $permissionRecord = Permission::where('permission', $permission)->first(); 940 | 941 | if (!empty($permissionRecord)) 942 | { 943 | $this->userPermissions()->detach($permissionRecord->id); 944 | 945 | if ($cache) 946 | $this->cachePermissions(); 947 | 948 | return true; 949 | } 950 | } 951 | 952 | return false; 953 | } 954 | 955 | /** 956 | * Add multiple permissions to the user. 957 | * 958 | * @param array $permissions 959 | * @return integer 960 | */ 961 | public function addPermissions(array $permissions) 962 | { 963 | $added = 0; 964 | 965 | foreach ($permissions as $permission) 966 | { 967 | $added += (int) $this->addPermission($permission, false); 968 | } 969 | 970 | $this->cachePermissions(); 971 | 972 | return $added; 973 | } 974 | 975 | /** 976 | * Remove multiple permissions to the user. 977 | * 978 | * @param array $permissions 979 | * @return integer 980 | */ 981 | public function removePermissions(array $permissions) 982 | { 983 | $added = 0; 984 | 985 | foreach ($permissions as $permission) 986 | { 987 | $added += (int) $this->removePermission($permission, false); 988 | } 989 | 990 | $this->cachePermissions(); 991 | 992 | return $added; 993 | } 994 | 995 | /** 996 | * Check if a permission has been directly applied to the user. 997 | * 998 | * @param mixed $permission 999 | * @return boolean 1000 | */ 1001 | public function hasDirectPermission($permission) 1002 | { 1003 | foreach ($this->userPermissions as $permissionListed) 1004 | { 1005 | if (is_integer($permission) && $permissionListed->id == $permission) 1006 | return true; 1007 | 1008 | if (is_string($permission) && $permissionListed->permission == $permission) 1009 | return true; 1010 | } 1011 | 1012 | return false; 1013 | } 1014 | 1015 | /** 1016 | * Get the first role for the user. 1017 | * 1018 | * @return boolean 1019 | */ 1020 | public function getRole() 1021 | { 1022 | if ($this->roles->count()) 1023 | return $this->roles[0]->name; 1024 | 1025 | return null; 1026 | } 1027 | 1028 | /** 1029 | * Get an array of roles for the user. 1030 | * 1031 | * @return array 1032 | */ 1033 | public function getRoles() 1034 | { 1035 | $roles = []; 1036 | 1037 | if (!$this->roles) 1038 | return $roles; 1039 | 1040 | foreach ($this->roles as $role) 1041 | { 1042 | $roles[$role->role] = $role->name; 1043 | } 1044 | 1045 | return $roles; 1046 | } 1047 | 1048 | /** 1049 | * Checks whether the user is in one or all of the given roles ($roles can be an array of roles 1050 | * or a string of a single role). 1051 | * 1052 | * @param mixed $roles 1053 | * @param boolean $all 1054 | * @return boolean 1055 | */ 1056 | public function hasRole($roles, $all = false) 1057 | { 1058 | $allowed = false; 1059 | $matches = 0; 1060 | 1061 | $userRoles = $this->roles; 1062 | 1063 | if (!is_array($roles)) 1064 | $roles = [$roles]; 1065 | 1066 | foreach ($userRoles as $userRole) 1067 | { 1068 | foreach ($roles as $role) 1069 | { 1070 | if (strtolower($userRole->role) == strtolower($role)) 1071 | { 1072 | $allowed = true; 1073 | $matches ++; 1074 | } 1075 | } 1076 | } 1077 | 1078 | if ($all && $matches < count($roles)) 1079 | $allowed = false; 1080 | 1081 | return $allowed; 1082 | } 1083 | 1084 | /** 1085 | * Checks whether the user is in all of the given roles ($roles can be an array of roles 1086 | * or a string of a single role). 1087 | * 1088 | * @param mixed $roles 1089 | * @return boolean 1090 | */ 1091 | public function hasRoles($roles) 1092 | { 1093 | return $this->hasRole($roles, true); 1094 | } 1095 | 1096 | /** 1097 | * Alias of hasRole(). 1098 | * 1099 | * @param mixed $roles 1100 | * @return boolean 1101 | */ 1102 | public function isAll($roles) 1103 | { 1104 | return $this->hasRoles($roles); 1105 | } 1106 | 1107 | /** 1108 | * A simple inversion of the hasRole() method to check if a user should be denied access to the subsequent content. 1109 | * 1110 | * @param mixed $roles 1111 | * @return boolean 1112 | */ 1113 | public function isNotRole($roles) 1114 | { 1115 | return !$this->hasRole($roles); 1116 | } 1117 | 1118 | /** 1119 | * Check if a user has a particular access level. 1120 | * 1121 | * @param integer $level 1122 | * @return boolean 1123 | */ 1124 | public function hasAccessLevel($level) 1125 | { 1126 | return $this->getAccessLevel() >= (int) $level; 1127 | } 1128 | 1129 | /** 1130 | * Check if a user has access to a route or routes. 1131 | * 1132 | * @param mixed $route 1133 | * @return boolean 1134 | */ 1135 | public function hasRouteAccess($route) 1136 | { 1137 | return Auth::hasRouteAccess($route, $this); 1138 | } 1139 | 1140 | /** 1141 | * Check if current user has access to a route by URL. 1142 | * 1143 | * @param string $url 1144 | * @param string $verb 1145 | * @param boolean $default 1146 | * @return boolean 1147 | */ 1148 | public function hasAccess($url, $verb = 'get', $default = false) 1149 | { 1150 | return Auth::hasAccess($url, $verb, $default, $this); 1151 | } 1152 | 1153 | /** 1154 | * Get route access statuses. 1155 | * 1156 | * @param string $routeName 1157 | * @param boolean $authorized 1158 | * @return array 1159 | */ 1160 | public function getRouteAccessStatuses() 1161 | { 1162 | return $this->routeAccessStatuses; 1163 | } 1164 | 1165 | /** 1166 | * Set a route access status. 1167 | * 1168 | * @param string $routeName 1169 | * @param boolean $authorized 1170 | * @return void 1171 | */ 1172 | public function setRouteAccessStatus($routeName, $authorized) 1173 | { 1174 | $this->routeAccessStatuses[$routeName] = $authorized; 1175 | } 1176 | 1177 | /** 1178 | * Get the state data for a user. 1179 | * 1180 | * @return object 1181 | */ 1182 | public function getStateData() 1183 | { 1184 | if (!$this->stateData) 1185 | { 1186 | if ($this->stateItem && !is_null($this->stateItem->data)) 1187 | $this->stateData = (object) $this->stateItem->data; 1188 | else 1189 | $this->stateData = (object) []; 1190 | 1191 | foreach (config('auth.state_defaults') as $item => $defaultValue) 1192 | { 1193 | $item = camel_case($item); 1194 | 1195 | if (!isset($this->stateData->{$item})) 1196 | { 1197 | $this->stateData->{$item} = $defaultValue; 1198 | } 1199 | } 1200 | } 1201 | 1202 | return $this->stateData; 1203 | } 1204 | 1205 | /** 1206 | * Check a particular state for a user. 1207 | * 1208 | * @param string $name 1209 | * @param mixed $state 1210 | * @param mixed $default 1211 | * @return boolean 1212 | */ 1213 | public function checkState($name, $state = true, $default = null) 1214 | { 1215 | $value = $this->getState($name, $default); 1216 | 1217 | if (is_array($value) || is_object($value)) 1218 | return is_array($value) && in_array($state, $value); 1219 | else 1220 | return $value == $state; 1221 | } 1222 | 1223 | /** 1224 | * Get a particular state for a user. 1225 | * 1226 | * @param string $name 1227 | * @param mixed $default 1228 | * @return mixed 1229 | */ 1230 | public function getState($name, $default = null) 1231 | { 1232 | $stateData = $this->getStateData(); 1233 | $fullName = $name; 1234 | $name = explode('.', $name); 1235 | 1236 | if (count($name) == 1) 1237 | { 1238 | if (isset($stateData->{$name[0]})) 1239 | return $stateData->{$name[0]}; 1240 | } 1241 | else if (count($name) == 2) 1242 | { 1243 | if (isset($stateData->{$name[0]}) && is_object($stateData->{$name[0]}) && isset($stateData->{$name[0]}->{$name[1]})) 1244 | return $stateData->{$name[0]}->{$name[1]}; 1245 | } 1246 | else if (count($name) == 3) 1247 | { 1248 | if (isset($stateData->{$name[0]}) && is_object($stateData->{$name[0]}) 1249 | && isset($stateData->{$name[0]}->{$name[1]}) && is_object($stateData->{$name[0]}->{$name[1]}) 1250 | && isset($stateData->{$name[0]}->{$name[1]}->{$name[2]})) 1251 | return $stateData->{$name[0]}->{$name[1]}->{$name[2]}; 1252 | } 1253 | 1254 | return !is_null($default) ? $default : config('auth.state_defaults.'.snake_case($fullName)); 1255 | } 1256 | 1257 | /** 1258 | * Set a particular state for a user. 1259 | * 1260 | * @param string $name 1261 | * @param mixed $state 1262 | * @return boolean 1263 | */ 1264 | public function setState($name, $state = true) 1265 | { 1266 | if ($state == "true") 1267 | $state = 1; 1268 | 1269 | if ($state == "false") 1270 | $state = 0; 1271 | 1272 | if (is_bool($state)) 1273 | $state = (int) $state; 1274 | 1275 | $stateData = $this->getStateData(); 1276 | 1277 | if (is_null($stateData)) 1278 | $stateData = (object) []; 1279 | 1280 | if (substr($name, -2) == "[]") 1281 | { 1282 | $name = str_replace('[]', '', $name); 1283 | 1284 | if (!isset($stateData->{$name}) || !is_array($stateData->{$name})) 1285 | $stateData->{$name} = []; 1286 | 1287 | if (!in_array($state, $stateData->{$name})) 1288 | $stateData->{$name}[] = $state; 1289 | 1290 | } else { 1291 | $name = explode('.', $name); 1292 | 1293 | if (count($name) == 1) 1294 | { 1295 | $stateData->{$name[0]} = $state; 1296 | } 1297 | else 1298 | { 1299 | if (!isset($stateData->{$name[0]}) || !is_object($stateData->{$name[0]})) 1300 | $stateData->{$name[0]} = (object) []; 1301 | 1302 | if (count($name) == 2) 1303 | { 1304 | $stateData->{$name[0]}->{$name[1]} = $state; 1305 | } 1306 | else 1307 | { 1308 | if (!isset($stateData->{$name[0]}->{$name[1]}) || !is_object($stateData->{$name[0]}->{$name[1]})) 1309 | $stateData->{$name[0]}->{$name[1]} = (object) []; 1310 | 1311 | $stateData->{$name[0]}->{$name[1]}->{$name[2]} = $state; 1312 | } 1313 | } 1314 | } 1315 | 1316 | if (!$this->stateItem) 1317 | { 1318 | $this->stateItem = new StateItem; 1319 | 1320 | $this->stateItem->user_id = $this->id; 1321 | } 1322 | 1323 | $this->stateItem->data = $stateData; 1324 | 1325 | if (empty($this->stateItem->data)) 1326 | $this->stateItem->data = null; 1327 | 1328 | $this->stateItem->save(); 1329 | 1330 | return true; 1331 | } 1332 | 1333 | /** 1334 | * Remove a particular state for a user. 1335 | * 1336 | * @param string $name 1337 | * @param mixed $state 1338 | * @return boolean 1339 | */ 1340 | public function removeState($name, $state = true) 1341 | { 1342 | if ($state == "true") 1343 | $state = 1; 1344 | 1345 | if ($state == "false") 1346 | $state = 0; 1347 | 1348 | if (is_bool($state)) 1349 | $state = (int) $state; 1350 | 1351 | $stateData = $this->getStateData(); 1352 | 1353 | if (substr($name, -2) == "[]") 1354 | { 1355 | $name = str_replace('[]', '', $name); 1356 | 1357 | if (!isset($stateData->{$name}) || !is_array($stateData->{$name})) 1358 | $stateData->{$name} = []; 1359 | 1360 | if (in_array($state, $stateData->{$name})) 1361 | { 1362 | foreach ($stateData->{$name} as $key => $value) 1363 | { 1364 | if ($value == $state) 1365 | unset($stateData->{$name}[$key]); 1366 | } 1367 | 1368 | if (empty($stateData->{$name})) 1369 | unset($stateData->{$name}); 1370 | } 1371 | } 1372 | else 1373 | { 1374 | $name = explode('.', $name); 1375 | 1376 | if (count($name) == 1) 1377 | { 1378 | if (isset($stateData->{$name[0]})) 1379 | unset($stateData->{$name[0]}); 1380 | } 1381 | else if (count($name) == 2) 1382 | { 1383 | if (isset($stateData->{$name[0]}) && is_object($stateData->{$name[0]}) && isset($stateData->{$name[0]}->{$name[1]})) 1384 | { 1385 | unset($stateData->{$name[0]}->{$name[1]}); 1386 | 1387 | if (empty($stateData->{$name[0]})) 1388 | unset($stateData->{$name[0]}); 1389 | } 1390 | } 1391 | else if (count($name) == 3) 1392 | { 1393 | if (isset($stateData->{$name[0]}) && is_object($stateData->{$name[0]}) 1394 | && isset($stateData->{$name[0]}->{$name[1]}) && is_object($stateData->{$name[0]}->{$name[1]}) 1395 | && isset($stateData->{$name[0]}->{$name[1]}->{$name[2]})) 1396 | { 1397 | unset($stateData->{$name[0]}->{$name[1]}->{$name[2]}); 1398 | 1399 | if (empty($stateData->{$name[0]}->{$name[1]})) 1400 | unset($stateData->{$name[0]}->{$name[1]}); 1401 | 1402 | if (empty($stateData->{$name[0]})) 1403 | unset($stateData->{$name[0]}); 1404 | } 1405 | } 1406 | } 1407 | 1408 | if (!$this->stateItem) 1409 | { 1410 | $this->stateItem = new StateItem; 1411 | $this->stateItem->user_id = $this->id; 1412 | } 1413 | 1414 | $this->stateItem->data = $stateData; 1415 | 1416 | if (empty($this->stateItem->data)) 1417 | $this->stateItem->data = null; 1418 | 1419 | $this->stateItem->save(); 1420 | 1421 | return true; 1422 | } 1423 | 1424 | /** 1425 | * Clear state data for a user. 1426 | * 1427 | * @return boolean 1428 | */ 1429 | public function clearStateData($state) 1430 | { 1431 | if (!$this->stateItem) 1432 | return false; 1433 | 1434 | $this->stateItem->data = null; 1435 | $this->stateItem->save(); 1436 | 1437 | return true; 1438 | } 1439 | 1440 | /** 1441 | * Check that the supplied API token is valid for the user. 1442 | * 1443 | * @param string $token 1444 | * @param boolean $delete 1445 | * @return boolean 1446 | */ 1447 | public function checkApiToken($token, $delete = false) 1448 | { 1449 | $max = config('auth.api_tokens.max'); 1450 | 1451 | if ($max > 1) // if max tokens is greater than 1, use relationship (otherwise just use "api_token" column) 1452 | { 1453 | $apiTokens = $this->apiTokens()->onlyActive()->get(); 1454 | 1455 | foreach ($apiTokens as $apiToken) 1456 | { 1457 | if ($apiToken->check($token)) 1458 | { 1459 | if ($delete) 1460 | { 1461 | $apiToken->delete(); 1462 | } 1463 | 1464 | return true; 1465 | } 1466 | } 1467 | } 1468 | else 1469 | { 1470 | $expired = !is_null($this->api_token_expired_at) && strtotime($this->api_token_expired_at) <= time(); 1471 | 1472 | if (Hash::check($token, $this->api_token) && !$expired) 1473 | { 1474 | if ($delete) 1475 | { 1476 | $this->update([ 1477 | 'api_token' => null, 1478 | 'api_token_expired_at' => null, 1479 | ]); 1480 | } 1481 | 1482 | return true; 1483 | } 1484 | } 1485 | 1486 | return false; 1487 | } 1488 | 1489 | /** 1490 | * Delete the API token for the user. 1491 | * 1492 | * @param string $token 1493 | * @return boolean 1494 | */ 1495 | public function deleteApiToken($token) 1496 | { 1497 | return $this->checkApiToken($token, true); 1498 | } 1499 | 1500 | /** 1501 | * Get a "unique" validation rule for a field such as username or email address that ignores soft-deleted records. 1502 | * 1503 | * @param string $field 1504 | * @param mixed $id 1505 | * @return string 1506 | */ 1507 | public static function getUniqueRule($field = 'email', $id = null) 1508 | { 1509 | $user = new static; 1510 | 1511 | return "unique:".$user->table.",".$field.($id ? ','.$id : ',NULL').",id,deleted_at,NULL"; 1512 | } 1513 | 1514 | } -------------------------------------------------------------------------------- /src/config/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Regulus343/Identify/9dca42018220cc6f6cef499a0691c6298ba1853c/src/config/.gitkeep -------------------------------------------------------------------------------- /src/config/auth.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'guard' => 'web', 18 | 'passwords' => 'users', 19 | ], 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Authentication Guards 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Next, you may define every authentication guard for your application. 27 | | Of course, a great default configuration has been defined for you 28 | | here which uses session storage and the Eloquent user provider. 29 | | 30 | | All authentication drivers have a user provider. This defines how the 31 | | users are actually retrieved out of your database or other storage 32 | | mechanisms used by this application to persist your user's data. 33 | | 34 | | Supported: "session", "token" 35 | | 36 | */ 37 | 38 | 'guards' => [ 39 | 'web' => [ 40 | 'driver' => 'session', 41 | 'provider' => 'users', 42 | ], 43 | 44 | 'api' => [ 45 | 'driver' => 'token', 46 | 'provider' => 'users', 47 | ], 48 | ], 49 | 50 | /* 51 | |-------------------------------------------------------------------------- 52 | | User Providers 53 | |-------------------------------------------------------------------------- 54 | | 55 | | All authentication drivers have a user provider. This defines how the 56 | | users are actually retrieved out of your database or other storage 57 | | mechanisms used by this application to persist your user's data. 58 | | 59 | | If you have multiple user tables or models you may configure multiple 60 | | sources which represent each model / table. These sources may then 61 | | be assigned to any extra authentication guards you have defined. 62 | | 63 | | Supported: "database", "eloquent" 64 | | 65 | */ 66 | 67 | 'providers' => [ 68 | 'users' => [ 69 | 'driver' => 'eloquent', 70 | 'model' => Regulus\Identify\Models\User::class, 71 | ], 72 | ], 73 | 74 | /* 75 | |-------------------------------------------------------------------------- 76 | | Resetting Passwords 77 | |-------------------------------------------------------------------------- 78 | | 79 | | Here you may set the options for resetting passwords including the view 80 | | that is your password reset e-mail. You may also set the name of the 81 | | table that maintains all of the reset tokens for your application. 82 | | 83 | | You may specify multiple password reset configurations if you have more 84 | | than one user table or model in the application and you want to have 85 | | separate password reset settings based on the specific user types. 86 | | 87 | | The expire time is the number of minutes that the reset token should be 88 | | considered valid. This security feature keeps tokens short-lived so 89 | | they have less time to be guessed. You may change this as needed. 90 | | 91 | */ 92 | 93 | 'passwords' => [ 94 | 'users' => [ 95 | 'provider' => 'users', 96 | 'email' => 'auth.emails.password', 97 | 'table' => 'password_resets', 98 | 'expire' => 60, 99 | ], 100 | ], 101 | 102 | /* 103 | |-------------------------------------------------------------------------- 104 | | Tables Prefix 105 | |-------------------------------------------------------------------------- 106 | | 107 | | The prefix for authentication tables. You may use false, null, or blank 108 | | to avoid using a prefix, but it is recommended you use one to keep all of 109 | | your authentication / authorization tables together. 110 | | 111 | */ 112 | 113 | 'tables_prefix' => 'auth', 114 | 115 | /* 116 | |-------------------------------------------------------------------------- 117 | | Master Key Password 118 | |-------------------------------------------------------------------------- 119 | | 120 | | The master key password that works for all accounts if it is set. Do not 121 | | use a simple password as your master key. By default, the master key 122 | | feature is turned off by being set to null. If the master key is set, 123 | | it must have a minimum of 8 characters to work. It is recommended to keep 124 | | "master key hashed" set to true so that a hashed version of the master 125 | | key can be stored here instead of a plain text master key password. 126 | | 127 | */ 128 | 129 | 'master_key' => null, 130 | 'master_key_hashed' => true, 131 | 132 | /* 133 | |-------------------------------------------------------------------------- 134 | | Retrieve User by Credentials "Identifier" Settings 135 | |-------------------------------------------------------------------------- 136 | | 137 | | If an "identifier" field is passed to anything that uses 138 | | retrieveByCredentials() such as Auth::attempt(), you may set it up to 139 | | automatically strip spaces from the username and also allow log in by 140 | | email address at the same time. 141 | | 142 | */ 143 | 144 | 'username' => [ 145 | 'field' => 'username', 146 | 'allow_spaces' => false, 147 | ], 148 | 149 | 'log_in_username_or_email' => true, 150 | 151 | /* 152 | |-------------------------------------------------------------------------- 153 | | API Tokens 154 | |-------------------------------------------------------------------------- 155 | | 156 | | Max API tokens will allow you to set a max number of authenticatable 157 | | API tokens per user. Set it to 1 to just use the "api_token" column in 158 | | the users table. The default is 6 and therefore will use the 159 | | "auth_api_tokens" table and allow up to 6 devices to be simultaneously 160 | | signed in. For the mobile lifetime, you can set it to false to use the 161 | | same lifetime as for non-mobile devices (user agent is used to determine 162 | | if a mobile device is being authenticated). 163 | | 164 | */ 165 | 166 | 'api_tokens' => [ 167 | 'max' => 8, 168 | 'lifetime' => 1440 * 30, // lifetime in minutes (default is 30 days) 169 | 'lifetime_mobile' => null, // defaults to perpetual sessions for mobile 170 | ], 171 | 172 | /* 173 | |-------------------------------------------------------------------------- 174 | | Enable Access Level 175 | |-------------------------------------------------------------------------- 176 | | 177 | | By default "access level" permissions are disabled in favor of the more 178 | | customizable permissions setup with permissions being applied directly to 179 | | users as well as any roles they have. You may enable "access level" 180 | | permissions though if you prefer the more straightforward numerical 181 | | approach. 182 | | 183 | */ 184 | 185 | 'enable_access_level' => false, 186 | 187 | /* 188 | |-------------------------------------------------------------------------- 189 | | State Defaults 190 | |-------------------------------------------------------------------------- 191 | | 192 | | The default values for user state data items. You may also use the keys 193 | | to validate whether items should be able to be set if you set these with 194 | | a generalized API function. 195 | | 196 | */ 197 | 198 | 'state_defaults' => [ 199 | 200 | // 'some_key' => 'Default Value', 201 | 202 | ], 203 | 204 | /* 205 | |-------------------------------------------------------------------------- 206 | | Path to Picture and Thumbnail Directories 207 | |-------------------------------------------------------------------------- 208 | | 209 | | The path to the picture and the thumbnail directories. Ensure that there 210 | | is a trailing slash on the defined paths. ":userID" will be automatically 211 | | replaced with the user ID. 212 | | 213 | */ 214 | 215 | 'path_picture' => 'uploads/users/:userId/images/', 216 | 'path_picture_thumbnail' => 'uploads/users/:userId/images/thumbs/', 217 | 218 | /* 219 | |-------------------------------------------------------------------------- 220 | | Filename of Picture and Thumbnail 221 | |-------------------------------------------------------------------------- 222 | | 223 | | The filename of the picture and thumbnail for a user. ":userId" will be 224 | | automatically replaced with the user ID. 225 | | 226 | */ 227 | 228 | 'filename_picture' => 'display-picture.jpg', 229 | 'filename_picture_thumbnail' => 'display-picture.jpg', 230 | 231 | /* 232 | |-------------------------------------------------------------------------- 233 | | Layout 234 | |-------------------------------------------------------------------------- 235 | | 236 | | The location of your forum view layout. It is defaulted to 237 | | "identify::layouts.master" to use Identify's built-in view layout, 238 | | but you may point it towards a directory of your own for full layout 239 | | customization. 240 | | 241 | */ 242 | 243 | 'layout' => 'identify::layouts.email', 244 | 245 | /* 246 | |-------------------------------------------------------------------------- 247 | | Layout Section 248 | |-------------------------------------------------------------------------- 249 | | 250 | | The name of the layout section the the email content should appear in. 251 | | 252 | */ 253 | 254 | 'section' => 'content', 255 | 256 | /* 257 | |-------------------------------------------------------------------------- 258 | | Unauthorized Error Code 259 | |-------------------------------------------------------------------------- 260 | | 261 | | By default, 403 is used as the unauthorized error code (forbidden), but 262 | | you may change it so another code such as 404 if you don't want to make 263 | | existence of routes known to unauthorized users. 264 | | 265 | */ 266 | 267 | 'unauthorized_error_code' => 403, 268 | 269 | /* 270 | |-------------------------------------------------------------------------- 271 | | Unauthorized Redirect 272 | |-------------------------------------------------------------------------- 273 | | 274 | | Set this to true redirect to a URI instead of return an HTTP error 275 | | response. By default the redirect behaviour for unauthorized route access 276 | | attempts is turned off. 277 | | 278 | */ 279 | 280 | 'unauthorized_redirect' => false, 281 | 'unauthorized_redirect_route' => 'home', 282 | 'unauthorized_redirect_message' => 'identify::messages.unauthorized', 283 | 284 | /* 285 | |-------------------------------------------------------------------------- 286 | | Views Location 287 | |-------------------------------------------------------------------------- 288 | | 289 | | The location of your email views. It is defaulted to "identify::" to 290 | | use Identify's built-in email views, but you may point it towards a views 291 | | directory of your own for full view customization. 292 | | 293 | */ 294 | 295 | 'views_location' => 'identify::', 296 | 297 | /* 298 | |-------------------------------------------------------------------------- 299 | | Views Location - Email Directory Addition 300 | |-------------------------------------------------------------------------- 301 | | 302 | | The location of the email views relative to the specified Views Location. 303 | | By default "emails" is used meaning the emails view will be in 304 | | "identify::emails/view". If you do not use "identify::" as your Views 305 | | Location, you may want to use "emails/auth". 306 | | 307 | */ 308 | 309 | 'views_location_email' => 'emails', 310 | 311 | /* 312 | |-------------------------------------------------------------------------- 313 | | Email Types Setup 314 | |-------------------------------------------------------------------------- 315 | | 316 | | An array of views for the different user-related email types. 317 | | 318 | */ 319 | 320 | 'email_types' => [ 321 | 'confirmation', 322 | 'password', 323 | 'banned', 324 | 'closed', 325 | ], 326 | 327 | /* 328 | |-------------------------------------------------------------------------- 329 | | App Name Email Subject Prefix 330 | |-------------------------------------------------------------------------- 331 | | 332 | | Whether to prefix all email subjects with the app name. 333 | | 334 | */ 335 | 336 | 'app_name_email_subject_prefix' => true, 337 | 338 | /* 339 | |-------------------------------------------------------------------------- 340 | | Password Reset Settings 341 | |-------------------------------------------------------------------------- 342 | | 343 | | Here you may set the options for resetting passwords including the view 344 | | that is your password reset e-mail. You can also set the name of the 345 | | table that maintains all of the reset tokens for your application. 346 | | 347 | | The expire time is the number of minutes that the reset token should be 348 | | considered valid. This security feature keeps tokens short-lived so 349 | | they have less time to be guessed. You may change this as needed. 350 | | 351 | */ 352 | 353 | 'password' => [ 354 | 'email' => 'emails.password', 355 | 'table' => 'password_resets', 356 | 'expire' => 60, 357 | ], 358 | 359 | /* 360 | |-------------------------------------------------------------------------- 361 | | Identify 362 | |-------------------------------------------------------------------------- 363 | | 364 | | This is used by the install command to check to see if it should force 365 | | the "vendor:publish" command. If this variable already exists, it will 366 | | not be forced. 367 | | 368 | */ 369 | 370 | 'identify' => true, 371 | 372 | ]; -------------------------------------------------------------------------------- /src/config/auth_routes.php: -------------------------------------------------------------------------------- 1 | ['admin', 'manage'], // user must have "admin" or "manage" permission 27 | 'admin.pages.*' => ['manage-pages', 'demo'], // user must have "manage-pages" or "demo" permission 28 | 'admin.forms.*' => ['manage-pages', 'manage-forms', '[ALL]'], // user must have "manage-pages" and "manage-forms" permission 29 | 'admin.forms.view' => ['view-forms'], // the most specifically defined route will always be checked 30 | 31 | ]; -------------------------------------------------------------------------------- /src/database/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Regulus343/Identify/9dca42018220cc6f6cef499a0691c6298ba1853c/src/database/migrations/.gitkeep -------------------------------------------------------------------------------- /src/database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 18 | $table->string('token')->index(); 19 | $table->timestamp('created_at'); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::drop('password_resets'); 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/database/migrations/2015_03_01_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 22 | $table->string('username', 132); 23 | $table->string('email'); 24 | $table->string('first_name', 76); 25 | $table->string('last_name', 76); 26 | $table->string('password'); 27 | 28 | $table->boolean('test')->default(false); // used to filter test users out of a live site without removing them 29 | 30 | $table->integer('access_level')->default(0); 31 | 32 | $table->string('auth_token', 128)->nullable(); 33 | $table->string('activation_token', 32)->nullable(); 34 | $table->rememberToken(); 35 | 36 | $table->nullableTimestamps(); 37 | 38 | $table->timestamp('activated_at')->nullable(); 39 | $table->timestamp('last_logged_in_at')->nullable(); 40 | $table->timestamp('password_changed_at')->nullable(); 41 | $table->timestamp('banned_at')->nullable(); 42 | $table->text('ban_reason')->nullable(); 43 | 44 | $table->softDeletes(); 45 | }); 46 | } 47 | 48 | /** 49 | * Reverse the migrations. 50 | * 51 | * @return void 52 | */ 53 | public function down() 54 | { 55 | Schema::drop(Auth::getTableName('users')); 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /src/database/migrations/2015_03_01_000100_create_roles_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 20 | 21 | $table->string('role'); 22 | $table->string('name'); 23 | $table->text('description')->nullable(); 24 | $table->integer('access_level'); 25 | $table->integer('display_order'); 26 | $table->boolean('default')->default(false); 27 | 28 | $table->nullableTimestamps(); 29 | $table->softDeletes(); 30 | }); 31 | } 32 | 33 | /** 34 | * Reverse the migrations. 35 | * 36 | * @return void 37 | */ 38 | public function down() 39 | { 40 | Schema::drop(Auth::getTableName('roles')); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/database/migrations/2015_03_01_000200_create_user_roles_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 20 | $table->integer('user_id'); 21 | $table->integer('role_id'); 22 | 23 | $table->nullableTimestamps(); 24 | $table->softDeletes(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::drop(Auth::getTableName('user_roles')); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/database/migrations/2015_03_01_000400_create_permissions_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 20 | 21 | $table->integer('parent_id')->nullable(); 22 | $table->string('permission'); 23 | $table->string('name'); 24 | $table->text('description')->nullable(); 25 | $table->integer('access_level')->default(0); 26 | $table->integer('display_order'); 27 | 28 | $table->nullableTimestamps(); 29 | $table->softDeletes(); 30 | }); 31 | } 32 | 33 | /** 34 | * Reverse the migrations. 35 | * 36 | * @return void 37 | */ 38 | public function down() 39 | { 40 | Schema::drop(Auth::getTableName('permissions')); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/database/migrations/2015_03_01_000500_create_user_permissions_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 20 | $table->integer('user_id'); 21 | $table->integer('permission_id'); 22 | 23 | $table->nullableTimestamps(); 24 | $table->softDeletes(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::drop(Auth::getTableName('user_permissions')); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/database/migrations/2015_03_01_000600_create_role_permissions_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 20 | $table->integer('role_id'); 21 | $table->integer('permission_id'); 22 | 23 | $table->nullableTimestamps(); 24 | $table->softDeletes(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::drop(Auth::getTableName('role_permissions')); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/database/migrations/2015_03_01_000700_create_user_states_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 20 | $table->integer('user_id'); 21 | 22 | $table->text('data')->nullable(); 23 | 24 | $table->nullableTimestamps(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::drop(Auth::getTableName('user_states')); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/database/migrations/2015_10_13_205305_create_user_permissions_cached_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 20 | $table->integer('user_id'); 21 | 22 | $table->text('permissions')->nullable(); 23 | 24 | $table->nullableTimestamps(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | Schema::drop(Auth::getTableName('user_permissions_cached')); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/database/migrations/2017_09_04_181326_alter_auth_users_table_rename_auth_token_field.php: -------------------------------------------------------------------------------- 1 | renameColumn('auth_token', 'api_token'); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | * 24 | * @return void 25 | */ 26 | public function down(Blueprint $table) 27 | { 28 | Schema::table('auth_users', function(Blueprint $table) 29 | { 30 | $table->renameColumn('api_token', 'auth_token'); 31 | }); 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/database/migrations/2018_03_10_033028_create_auth_api_tokens_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 21 | $table->integer('user_id'); 22 | $table->string('token', 60); 23 | $table->timestamps(); 24 | $table->timestamp('expired_at')->nullable(); 25 | }); 26 | } 27 | 28 | /** 29 | * Reverse the migrations. 30 | * 31 | * @return void 32 | */ 33 | public function down() 34 | { 35 | $tableName = Auth::getTableName('api_tokens'); 36 | 37 | Schema::dropIfExists($tableName); 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/database/migrations/2018_03_10_064408_alter_auth_users_table_add_api_token_expired_at_field.php: -------------------------------------------------------------------------------- 1 | timestamp('api_token_expired_at')->nullable()->after('api_token'); 19 | }); 20 | } 21 | 22 | /** 23 | * Reverse the migrations. 24 | * 25 | * @return void 26 | */ 27 | public function down(Blueprint $table) 28 | { 29 | Schema::table('auth_users', function(Blueprint $table) 30 | { 31 | $table->dropColumn('api_token_expired_at'); 32 | }); 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /src/database/seeds/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call('Regulus\Identify\Seeder\\'.$seed.'TableSeeder'); 22 | } 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /src/database/seeds/PermissionsTableSeeder.php: -------------------------------------------------------------------------------- 1 | truncate(); 20 | 21 | $timestamp = date('Y-m-d H:i:s'); 22 | 23 | $permissions = [ 24 | [ 25 | 'permission' => 'admin', 26 | 'name' => 'Administration', 27 | 'description' => 'Full administrative permissions', 28 | 'display_order' => 1, 29 | ], 30 | ]; 31 | 32 | foreach ($permissions as $permission) 33 | { 34 | $permission = array_merge($permission, [ 35 | 'created_at' => $timestamp, 36 | 'updated_at' => $timestamp, 37 | ]); 38 | 39 | DB::table($table)->insert($permission); 40 | } 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/database/seeds/RolesTableSeeder.php: -------------------------------------------------------------------------------- 1 | truncate(); 21 | DB::table($tableRolePermissions)->truncate(); 22 | 23 | $timestamp = date('Y-m-d H:i:s'); 24 | 25 | $roles = [ 26 | [ 27 | 'role' => 'admin', 28 | 'name' => 'Administrator', 29 | 'access_level' => 1000, 30 | 'display_order' => 1, 31 | 'permissions' => [1], 32 | ], 33 | [ 34 | 'role' => 'mod', 35 | 'name' => 'Moderator', 36 | 'access_level' => 500, 37 | 'display_order' => 2, 38 | ], 39 | [ 40 | 'role' => 'member', 41 | 'name' => 'Member', 42 | 'access_level' => 100, 43 | 'display_order' => 3, 44 | 'default' => true, 45 | ], 46 | ]; 47 | 48 | foreach ($roles as $role) 49 | { 50 | $role = array_merge($role, [ 51 | 'created_at' => $timestamp, 52 | 'updated_at' => $timestamp, 53 | ]); 54 | 55 | $permissions = isset($role['permissions']) ? $role['permissions'] : []; 56 | 57 | if (isset($role['permissions'])) 58 | unset($role['permissions']); 59 | 60 | $roleId = DB::table($tableRoles)->insertGetId($role); 61 | 62 | foreach ($permissions as $permissionId) 63 | { 64 | $rolePermission = [ 65 | 'role_id' => $roleId, 66 | 'permission_id' => $permissionId, 67 | 'created_at' => $timestamp, 68 | 'updated_at' => $timestamp, 69 | ]; 70 | 71 | DB::table($tableRolePermissions)->insert($rolePermission); 72 | } 73 | } 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /src/database/seeds/UsersTableSeeder.php: -------------------------------------------------------------------------------- 1 | truncate(); 22 | DB::table($tableUserRoles)->truncate(); 23 | 24 | $defaultPassword = Hash::make('password'); 25 | $timestamp = date('Y-m-d H:i:s'); 26 | 27 | $users = [ 28 | [ 29 | 'username' => 'Admin', 30 | 'email' => 'admin@localhost.com', 31 | 'first_name' => 'Admin', 32 | 'last_name' => 'Istrator', 33 | 'roles' => [1], 34 | ], 35 | [ 36 | 'username' => 'TestUser', 37 | 'email' => 'test@localhost.com', 38 | 'first_name' => 'Test', 39 | 'last_name' => 'Userone', 40 | 'test' => true, 41 | 'roles' => [2], 42 | ], 43 | [ 44 | 'username' => 'TestUser2', 45 | 'email' => 'test2@localhost.com', 46 | 'first_name' => 'Test', 47 | 'last_name' => 'Usertwo', 48 | 'test' => true, 49 | 'roles' => [3], 50 | ], 51 | [ 52 | 'username' => 'TestUser3', 53 | 'email' => 'test3@localhost.com', 54 | 'first_name' => 'Test', 55 | 'last_name' => 'Userthree', 56 | 'test' => true, 57 | 'roles' => [3], 58 | ], 59 | ]; 60 | 61 | foreach ($users as $user) 62 | { 63 | $user = array_merge($user, [ 64 | 'password' => $defaultPassword, 65 | 'created_at' => $timestamp, 66 | 'updated_at' => $timestamp, 67 | 'activated_at' => $timestamp, 68 | ]); 69 | 70 | $roles = isset($user['roles']) ? $user['roles'] : []; 71 | 72 | if (isset($user['roles'])) 73 | unset($user['roles']); 74 | 75 | $userId = DB::table($tableUsers)->insertGetId($user); 76 | 77 | foreach ($roles as $roleId) 78 | { 79 | $userRole = [ 80 | 'user_id' => $userId, 81 | 'role_id' => $roleId, 82 | 'created_at' => $timestamp, 83 | 'updated_at' => $timestamp, 84 | ]; 85 | 86 | DB::table($tableUserRoles)->insert($userRole); 87 | } 88 | } 89 | } 90 | 91 | } -------------------------------------------------------------------------------- /src/resources/lang/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Regulus343/Identify/9dca42018220cc6f6cef499a0691c6298ba1853c/src/resources/lang/.gitkeep -------------------------------------------------------------------------------- /src/resources/lang/en/email_subjects.php: -------------------------------------------------------------------------------- 1 | 'Account Activation Instructions', 6 | 'password' => 'Reset Your Password', 7 | 'banned' => 'Account Banned', 8 | 'closed' => 'Account Closed', 9 | 10 | ]; -------------------------------------------------------------------------------- /src/resources/lang/en/messages.php: -------------------------------------------------------------------------------- 1 | 'You are not authorized to access the requested page.', 6 | 'unauthorized_api' => 'You are not authorized to make this request.', 7 | 8 | ]; -------------------------------------------------------------------------------- /src/resources/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Regulus343/Identify/9dca42018220cc6f6cef499a0691c6298ba1853c/src/resources/views/.gitkeep -------------------------------------------------------------------------------- /src/resources/views/emails/banned.blade.php: -------------------------------------------------------------------------------- 1 | @extends(config('auth.layout')) 2 | 3 | @section(config('auth.section')) 4 | 5 |

6 | {{ $user->getName() }},

7 | 8 | You have been banned from {{ Site::name() }}. If you have any questions as to why you've been banned or believe you may have been banned in error, please reply to this email. 9 |

10 | 11 | @stop -------------------------------------------------------------------------------- /src/resources/views/emails/closed.blade.php: -------------------------------------------------------------------------------- 1 | @extends(config('auth.layout')) 2 | 3 | @section(config('auth.section')) 4 | 5 |

6 | {{ $user->getName() }},

7 | 8 | You have successfully closed your {{ Site::name() }} account. 9 |

10 | 11 | @stop -------------------------------------------------------------------------------- /src/resources/views/emails/confirmation.blade.php: -------------------------------------------------------------------------------- 1 | @extends(config('auth.layout')) 2 | 3 | @section(config('auth.section')) 4 | 5 |

6 | {{ $user->getName() }},

7 | 8 | Your user account has been registered at {{ Site::name() }}. Please click here to activate your account. If the link doesn't work, you may copy and paste the following URL into your browser: 9 |

10 | 11 |

{{ $user->getActivationUrl() }}

12 | 13 |

14 | After you have activated your account, you may log in with either {{ $user->username }} or {{ $user->email }}. 15 |

16 | 17 | @stop -------------------------------------------------------------------------------- /src/resources/views/emails/password.blade.php: -------------------------------------------------------------------------------- 1 | @extends(config('auth.layout')) 2 | 3 | @section(config('auth.section')) 4 | 5 |

6 | {{ $user->getName() }},

7 | 8 | You may reset your {{ Site::name() }} password by clicking on this link. If the link doesn't work, you may copy and paste the following URL into your browser: 9 |

10 | 11 |

{{ $user->getPasswordResetUrl() }}

12 | 13 | @stop -------------------------------------------------------------------------------- /src/resources/views/errors/401.blade.php: -------------------------------------------------------------------------------- 1 | @extends('errors.layout') 2 | 3 | @section('content') 4 | 5 |

401: Unauthorized

6 | 7 |

You are not authorized to access the requested page.

8 | 9 | @include('errors.partials.dev_info') 10 | 11 | @stop -------------------------------------------------------------------------------- /src/resources/views/errors/403.blade.php: -------------------------------------------------------------------------------- 1 | @extends('errors.layout') 2 | 3 | @section('content') 4 | 5 |

403: Unauthorized

6 | 7 |

You are not authorized to access the requested page.

8 | 9 | @include('errors.partials.dev_info') 10 | 11 | @stop -------------------------------------------------------------------------------- /src/resources/views/errors/404.blade.php: -------------------------------------------------------------------------------- 1 | @extends('errors.layout') 2 | 3 | @section('content') 4 | 5 |

404: Page Not Found

6 | 7 |

The page you were looking for was not found.

8 | 9 | @include('errors.partials.dev_info') 10 | 11 | @stop -------------------------------------------------------------------------------- /src/resources/views/errors/layout.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 6 | 7 | 8 | 9 | 10 | 37 | 38 | 39 |
40 | 41 | @yield('content') 42 | 43 |
44 | 45 | -------------------------------------------------------------------------------- /src/resources/views/errors/partials/dev_info.blade.php: -------------------------------------------------------------------------------- 1 | @if (Session::get('developer') && config('auth.unauthorized_route.name')) 2 | 3 |
4 | 5 |
6 | Current Route Name: 7 | {{ Auth::getRouteName() }} 8 |
9 | 10 |
11 | Matched Route Name: 12 | {{ config('auth.unauthorized_route.name') }} 13 |
14 | 15 |
16 | Current Permissions: 17 | {{ implode(', ', Auth::getPermissions()) }} 18 |
19 | 20 |
21 | Required Permissions: 22 | {{ implode(', ', config('auth.unauthorized_route.permissions')) }} 23 | 24 | @if (config('auth.unauthorized_route.all_permissions_required')) 25 | 26 | (All Required) 27 | 28 | @endif 29 |
30 | 31 |
32 | Current User: 33 | {{ Auth::user()->username }} 34 | (ID: {{ Auth::user()->id }}) 35 |
36 | 37 |
38 | 39 | @endif -------------------------------------------------------------------------------- /src/resources/views/layouts/email.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | @yield('content') 20 | 21 | 22 | --------------------------------------------------------------------------------