├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── composer.lock ├── config └── laravel-impersonate-ui.php ├── resources └── views │ └── impersonate-ui.blade.php ├── screenshot.png └── src ├── Controllers └── ImpersonateUiController.php ├── ImpersonateUi.php ├── ImpersonateUiServiceProvider.php ├── Middlewares └── ImpersonateUiMiddleware.php └── Routes └── ImpersonateUiRoutes.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | node_modules/ 3 | npm-debug.log 4 | 5 | # Laravel 4 specific 6 | bootstrap/compiled.php 7 | app/storage/ 8 | 9 | # Laravel 5 & Lumen specific 10 | public/storage 11 | public/hot 12 | storage/*.key 13 | .env.*.php 14 | .env.php 15 | .env 16 | Homestead.yaml 17 | Homestead.json 18 | 19 | # Rocketeer PHP task runner and deployment package. https://github.com/rocketeers/rocketeer 20 | .rocketeer/ 21 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.2 5 | - 7.3 6 | - 7.4snapshot 7 | 8 | matrix: 9 | include: 10 | - php: 7.2 11 | env: COMPOSER_FLAGS="--prefer-lowest" 12 | allow_failures: 13 | - php: 7.4snapshot 14 | 15 | before_script: 16 | - travis_retry composer self-update 17 | - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction 18 | 19 | script: 20 | - vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Hapidjus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Licence: MIT](https://img.shields.io/badge/License-MIT-yellow.svg) 2 | # Laravel Impersonate UI 3 | 4 | Laravel Impersonate UI is a Laravel Package that adds an easy to use UI for selecting users to impersonate when using https://github.com/404labfr/laravel-impersonate 5 | 6 | ![Demo](https://raw.githubusercontent.com/hapidjus/laravel-impersonate-ui/master/screenshot.png) 7 | 8 | ### Requirements 9 | - Laravel >= 6.1 10 | - PHP >= 7.1 11 | 12 | 13 | ### Installation 14 | - Require laravel-impersonate-ui with Composer 15 | ```php 16 | composer require hapidjus/laravel-impersonate-ui 17 | ``` 18 | 19 | - Add the Trait `Lab404\Impersonate\Models\Impersonate` to your __User__ model. 20 | 21 | ```php 22 | env('APP_DEBUG',false), 61 | 62 | /** 63 | * Users allowed to impersonate 64 | * 65 | * Array of user emails, i.e ['admin@example.com'] or null for all 66 | * 67 | */ 68 | 'users_allowed_to_impersonate' => ['admin@example.com'], 69 | 70 | /** 71 | * Position of icon. 72 | * 73 | * Supported: "bottom-right", "bottom-left", "top-left", "top-right" 74 | * 75 | */ 76 | 'icon_position' => 'bottom-right', 77 | 78 | /** 79 | * Show Impersonate button. 80 | * 81 | * Trying to save some clicks? 82 | * Then this is the option for you! Select a user and BOOM - 83 | * form submitted - user impersonated. No need to click any 84 | * pesky buttons. 85 | * 86 | */ 87 | 'show_button' => true, 88 | 89 | /** 90 | * Globally include laravel-impersonate-ui. 91 | * 92 | * Or use this view: @include('impersonate-ui::impersonate-ui') 93 | * Note: If you choose to include the partials view you need to add 94 | * a check to test if the current users is allowed 95 | * to impersonate 96 | */ 97 | 'global_include' => true, 98 | 99 | /** 100 | * The URI/Route to redirect after taking an impersonation. 101 | * 102 | * Use 'back' to redirect to the previous page 103 | * 104 | */ 105 | 'take_redirect_to' => 'back', 106 | 107 | /** 108 | * The URI/Route to redirect after leaving an impersonation. 109 | * 110 | * Use 'back' to redirect to the previous page 111 | * 112 | */ 113 | 'leave_redirect_to' => 'back', 114 | 115 | /** 116 | * Only allow these users to be impersonated 117 | * 118 | * Array of user IDs or null for all 119 | * 120 | */ 121 | 'users_only' => null, 122 | 123 | /** 124 | * Exlude these users from beeing impersonated 125 | * 126 | * Array of user IDs or null for none 127 | * 128 | */ 129 | 'users_exclude' => null, 130 | 131 | ]; 132 | ``` 133 | 134 | ### Partials view: 135 | 136 | You can use the partials view to include the Impersonate UI on any pages you want. 137 | Note: If you choose to include the partials view you need to add a check to test if the current users is allowed to impersonate 138 | 139 | ```php 140 | @include('impersonate-ui::impersonate-ui') 141 | ``` 142 | 143 | Have fun impersonating. 144 | 145 | 146 | Do not use in production! 147 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hapidjus/laravel-impersonate-ui", 3 | "type": "library", 4 | "description": "UI for 404labfr/laravel-impersonate", 5 | "keywords": [ 6 | "laravel", 7 | "package", 8 | "plugin", 9 | "impersonate", 10 | "impersonation", 11 | "user", 12 | "auth", 13 | "laravel-package", 14 | "laravel-plugin" 15 | ], 16 | "homepage": "https://github.com/hapidjus/laravel-impersonate-ui", 17 | "license": "MIT", 18 | "authors": [ 19 | { 20 | "name": "hapidjus", 21 | "email": "hapidjus@caesardev.se" 22 | } 23 | ], 24 | "require": { 25 | "php": ">=7.1.3", 26 | "laravel/framework": "^7.0|^8.0|^9.0|^10.0", 27 | "lab404/laravel-impersonate": "~1.7" 28 | }, 29 | "require-dev": { 30 | "mockery/mockery": "^1.0", 31 | "phpunit/phpunit": "^7.0|^8.0|^9.0||^10.0" 32 | }, 33 | "autoload": { 34 | "psr-4": { 35 | "Hapidjus\\ImpersonateUI\\": "src/" 36 | } 37 | }, 38 | "extra": { 39 | "laravel": { 40 | "providers": [ 41 | "Hapidjus\\ImpersonateUI\\ImpersonateUiServiceProvider" 42 | ] 43 | } 44 | }, 45 | "minimum-stability": "dev", 46 | "prefer-stable": true 47 | } -------------------------------------------------------------------------------- /config/laravel-impersonate-ui.php: -------------------------------------------------------------------------------- 1 | env('APP_DEBUG',false), 12 | 13 | /** 14 | * User Model Class. 15 | * 16 | * Defaults to : '\App\Models\User' in accordance with Laravel 8 17 | * convention 18 | * 19 | */ 20 | 'user_model' => '\App\Models\User', 21 | 22 | /** 23 | * Users allowed to impersonate 24 | * 25 | * Array of user emails, i.e ['admin@example.com'] or null for all 26 | * 27 | */ 28 | 'users_allowed_to_impersonate' => ['admin@example.com'], 29 | 30 | /** 31 | * Position of icon. 32 | * 33 | * Supported: "bottom-right", "bottom-left", "top-left", "top-right" 34 | * 35 | */ 36 | 'icon_position' => 'bottom-right', 37 | 38 | /** 39 | * Show Impersonate button. 40 | * 41 | * Trying to save some clicks? 42 | * Then this is the option for you! Select a user and BOOM - 43 | * form submitted - user impersonated. No need to click any 44 | * pesky buttons. 45 | * 46 | */ 47 | 'show_button' => true, 48 | 49 | /** 50 | * Globally include laravel-impersonate-ui. 51 | * 52 | * Or use this view: @include('impersonate-ui::impersonate-ui') 53 | * Note: If you include the view yourself you need to add 54 | * a check yourself to test if the current users is allowed 55 | * to impersonate 56 | */ 57 | 'global_include' => true, 58 | 59 | /** 60 | * The URI/Route to redirect after taking an impersonation. 61 | * 62 | * Use 'back' to redirect to the previous page 63 | * 64 | */ 65 | 'take_redirect_to' => 'back', 66 | 67 | /** 68 | * The URI/Route to redirect after leaving an impersonation. 69 | * 70 | * Use 'back' to redirect to the previous page 71 | * 72 | */ 73 | 'leave_redirect_to' => 'back', 74 | 75 | /** 76 | * Only allow these users to be impersonated 77 | * 78 | * Array of user IDs or null for all 79 | * 80 | */ 81 | 'users_only' => null, 82 | 83 | /** 84 | * Exlude these users from beeing impersonated 85 | * 86 | * Array of user IDs or null for none 87 | * 88 | */ 89 | 'users_exclude' => null, 90 | 91 | ]; 92 | -------------------------------------------------------------------------------- /resources/views/impersonate-ui.blade.php: -------------------------------------------------------------------------------- 1 | @canImpersonate 2 |
3 | 4 | {!! '' !!} 5 | 6 |
7 |

Laravel Impersonate UI

8 | Logged on as: {{ Auth::user()->name }}
9 | @impersonating 10 | Real user: {{ $impersonator->name }} 11 | @endImpersonating 12 |
13 | @csrf 14 |
15 | 16 | 17 | 26 |
27 |
28 | @if(config('laravel-impersonate-ui.show_button')) 29 | 30 | @endif 31 | 32 | @impersonating 33 | Leave 34 | @endImpersonating 35 |
36 | 37 |
38 | X 39 | 40 |
41 |
42 | 43 | 119 | 125 | @endCanImpersonate -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hapidjus/laravel-impersonate-ui/193da9384d72916e42542230e5fbbe4017c2b270/screenshot.png -------------------------------------------------------------------------------- /src/Controllers/ImpersonateUiController.php: -------------------------------------------------------------------------------- 1 | manager = app('impersonate'); 20 | $this->uiManager = app('impersonateUi'); 21 | 22 | } 23 | 24 | public function take(Request $request) 25 | { 26 | 27 | if (! $request->user()->canImpersonate()) { 28 | abort(403); 29 | } 30 | 31 | 32 | if(! $this->uiManager->userAllowedToImpersonate()){ 33 | abort(403); 34 | } 35 | 36 | if($this->manager->isImpersonating()) 37 | { 38 | $this->manager->leave(); 39 | } 40 | 41 | $userToImpersonate = $this->manager->findUserById($request->impersonate_id); 42 | 43 | if ($userToImpersonate->canBeImpersonated()) { 44 | 45 | $this->manager->take($request->user(), $userToImpersonate); 46 | 47 | } 48 | 49 | return $this->uiManager->makeTakeRedirectTo(); 50 | 51 | } 52 | 53 | public function leave(Request $request) 54 | { 55 | 56 | if($this->manager->isImpersonating()) 57 | { 58 | 59 | $this->manager->leave(); 60 | 61 | } 62 | 63 | return $this->uiManager->makeLeaveRedirectTo(); 64 | 65 | } 66 | 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/ImpersonateUi.php: -------------------------------------------------------------------------------- 1 | app = $app; 16 | $this->manager = $this->app['impersonate']; 17 | } 18 | 19 | public function userAllowedToImpersonate(){ 20 | 21 | if(! auth()->user()){ 22 | return false; 23 | } 24 | 25 | if($this->manager->isImpersonating()){ 26 | return true; 27 | } 28 | 29 | if(! is_array(config('laravel-impersonate-ui.users_allowed_to_impersonate'))){ 30 | return true; 31 | } 32 | 33 | return in_array(auth()->user()->email, config('laravel-impersonate-ui.users_allowed_to_impersonate')); 34 | 35 | } 36 | 37 | public function getImpersonator(){ 38 | 39 | if($this->manager->getImpersonatorId() !== null) 40 | { 41 | return config('laravel-impersonate-ui.user_model')::findOrFail($this->manager->getImpersonatorId()); 42 | 43 | } 44 | 45 | return null; 46 | 47 | } 48 | 49 | public function makeTakeRedirectTo(){ 50 | 51 | $takeRedirect = $this->getTakeRedirectTo(); 52 | 53 | if ($this->getTakeRedirectTo() !== 'back') { 54 | 55 | return redirect()->to($takeRedirect); 56 | 57 | } 58 | 59 | return back(); 60 | 61 | } 62 | public function getTakeRedirectTo(){ 63 | 64 | try { 65 | 66 | $uri = route(config('laravel-impersonate-ui.take_redirect_to')); 67 | 68 | } catch (\InvalidArgumentException $e) { 69 | 70 | $uri = config('laravel-impersonate-ui.take_redirect_to'); 71 | 72 | } 73 | 74 | return $uri; 75 | 76 | } 77 | 78 | public function makeLeaveRedirectTo(){ 79 | 80 | $leaveRedirect = $this->getLeaveRedirectTo(); 81 | 82 | if ($leaveRedirect !== 'back') { 83 | 84 | return redirect()->to($leaveRedirect); 85 | 86 | } 87 | 88 | return back(); 89 | 90 | } 91 | 92 | public function getLeaveRedirectTo(){ 93 | 94 | try { 95 | 96 | $uri = route(config('laravel-impersonate-ui.leave_redirect_to')); 97 | 98 | } catch (\InvalidArgumentException $e) { 99 | 100 | $uri = config('laravel-impersonate-ui.leave_redirect_to'); 101 | 102 | } 103 | 104 | return $uri; 105 | } 106 | 107 | static public function getUsers(){ 108 | 109 | if(is_array(config('laravel-impersonate-ui.users_only'))){ 110 | return config('laravel-impersonate-ui.user_model')::whereIn('id', config('laravel-impersonate-ui.users_only'))->orderBy('name')->get(); 111 | } 112 | 113 | if(is_array(config('laravel-impersonate-ui.users_exclude'))){ 114 | return config('laravel-impersonate-ui.user_model')::whereNotIn('id', config('laravel-impersonate-ui.users_exclude'))->orderBy('name')->get(); 115 | } 116 | 117 | return config('laravel-impersonate-ui.user_model')::orderBy('name')->get(); 118 | 119 | } 120 | 121 | } -------------------------------------------------------------------------------- /src/ImpersonateUiServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadViewsFrom(__DIR__ . '/../resources/views', 'impersonate-ui'); 24 | 25 | $this->publishes([ 26 | __DIR__.'/../config/laravel-impersonate-ui.php' => config_path('laravel-impersonate-ui.php'), 27 | ], 28 | 'config' 29 | ); 30 | 31 | $this->publishes([ 32 | __DIR__.'/../resources/views' => resource_path('views/vendor/impersonate-ui'), 33 | ], 34 | 'view' 35 | ); 36 | } 37 | 38 | /** 39 | * Register bindings in the container. 40 | * 41 | * @return void 42 | */ 43 | public function register() 44 | { 45 | 46 | $this->mergeConfig(); 47 | 48 | if(! $this->isEnabled()){ 49 | return; 50 | } 51 | 52 | $this->app->singleton(ImpersonateUi::class, function ($app) { 53 | return new ImpersonateUi($app); 54 | }); 55 | $this->app->alias(ImpersonateUi::class, 'impersonateUi'); 56 | 57 | 58 | app('Illuminate\Contracts\Http\Kernel')->pushMiddleware(ImpersonateUiMiddleware::class); 59 | 60 | $this->registerViewComposer(); 61 | 62 | $this->registerRoutes(); 63 | 64 | 65 | } 66 | 67 | protected function registerViewComposer() 68 | { 69 | View::composer('impersonate-ui::impersonate-ui', function ($view) { 70 | 71 | $view->with([ 72 | 'impersonator' => app('impersonate')->getImpersonator(), 73 | 'users' => ImpersonateUi::getUsers() 74 | ]); 75 | 76 | }); 77 | 78 | } 79 | 80 | protected function isEnabled() 81 | { 82 | return config('laravel-impersonate-ui.enabled', false); 83 | } 84 | 85 | protected function registerRoutes() 86 | { 87 | $this->loadRoutesFrom(__DIR__.'/Routes/ImpersonateUiRoutes.php'); 88 | } 89 | 90 | protected function mergeConfig() 91 | { 92 | $this->mergeConfigFrom(__DIR__.'/../config/laravel-impersonate-ui.php', 'laravel-impersonate-ui'); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/Middlewares/ImpersonateUiMiddleware.php: -------------------------------------------------------------------------------- 1 | headers->get('Content-Type'), 'text/html')) { 29 | return $response; 30 | } 31 | 32 | $this->uiManager = app('impersonateUi'); 33 | 34 | if(! $this->uiManager->userAllowedToImpersonate()){ 35 | return $response; 36 | } 37 | 38 | $content = $response->getContent(); 39 | 40 | if (($head = mb_strpos($content, '')) !== false) { 41 | 42 | $response->setContent(mb_substr($content, 0, $head) . 43 | view('impersonate-ui::impersonate-ui') . 44 | mb_substr($content, $head)); 45 | 46 | } 47 | 48 | return $response; 49 | 50 | } 51 | 52 | public function getImpersonator(){ 53 | 54 | $manager = app('impersonate'); 55 | 56 | if($manager->getImpersonatorId() !== null) 57 | { 58 | return config('laravel-impersonate-ui.user_model')::findOrFail($manager->getImpersonatorId()); 59 | 60 | } 61 | 62 | return null; 63 | 64 | } 65 | } -------------------------------------------------------------------------------- /src/Routes/ImpersonateUiRoutes.php: -------------------------------------------------------------------------------- 1 | ['web']], function () { 3 | Route::post('impersonate-ui', 'Hapidjus\ImpersonateUI\Controllers\ImpersonateUiController@take')->name('impersonate-ui.take'); 4 | Route::get('impersonate-ui', 'Hapidjus\ImpersonateUI\Controllers\ImpersonateUiController@leave')->name('impersonate-ui.leave'); 5 | }); 6 | 7 | --------------------------------------------------------------------------------