Sometimes it's useful for the admin to see everything from the user's perspective. To see exactly what he sees. With an admin panel lik...
Sometimes it's useful for the admin to see everything from the user's perspective. To see exactly what he sees. With an admin panel like Backpack, it's not too difficult to add this functionality.
Assumptions:
app\Http\Models\Traits\CanImpersonateTrait.php
:<?php namespace App\Models\Traits;
use Illuminate\Database\Eloquent\Model;
use Session;
trait CanImpersonateTrait
{
public function setImpersonating($id)
{
Session::put('impersonate', $id);
}
public function stopImpersonating()
{
Session::forget('impersonate');
}
public function isImpersonating()
{
return Session::has('impersonate');
}
}
User.php
model:class User extends Authenticatable
{
use Notifiable;
use CrudTrait;
use HasRoles;
use \App\Models\Traits\CanImpersonateTrait;
@if (Auth::user()->isImpersonating())
<li><a href="{{ url('stop-impersonating') }}">Stop Impersonating</a></li>
@endif
and a route to go with it (inside your auth middleware or wherever else you have your logged in routes):
Route::get('stop-impersonating', function() {
backpack_user()->stopImpersonating();
\Alert::success('Impersonating stopped.')->flash();
return redirect()->back();
});
routes/backpack/permissionmanager.php
file, where you copy-paste the contents of the package routes, and comment out the route to the UserCrudController:<?php
/*
|--------------------------------------------------------------------------
| Backpack\PermissionManager Routes
|--------------------------------------------------------------------------
|
| This file is where you may define all of the routes that are
| handled by the Backpack\PermissionManager package.
|
*/
Route::group([
'namespace' => 'Backpack\PermissionManager\app\Http\Controllers',
'prefix' => config('backpack.base.route_prefix', 'admin'),
'middleware' => ['web', backpack_middleware()],
], function () {
Route::crud('permission', 'PermissionCrudController');
Route::crud('role', 'RoleCrudController');
// Route::crud('user', 'UserCrudController'); // removed and placed within the backpack/custom routes files
});
Next let's add that route to our routes/backpack/custom.php
:
// ... inside Route::group() and everything so it's only shown to admins
// Overwritten CRUD packages
Route::crud('user', 'UserCrudController');
This will point the route to a controller we create now, app/Http/Controllers/Admin/UserCrudController.php
:
<?php
namespace App\Http\Controllers\Admin;
use Backpack\CRUD\app\Http\Controllers\CrudController;
use Backpack\PermissionManager\app\Http\Controllers\UserCrudController as OriginalUserCrudController;
use App\Http\Controllers\Admin\Operations\ImpersonateOperation;
// VALIDATION: change the requests to match your own file names if you need form validation
use App\Http\Requests\ArticleRequest as StoreRequest;
use App\Http\Requests\ArticleRequest as UpdateRequest;
class UserCrudController extends OriginalUserCrudController
{
use ImpersonateOperation;
}
app/Http/Controllers/Admin/Operations/ImpersonateOperation.php
:<?php
namespace App\Http\Controllers\Admin\Operations;
use Illuminate\Support\Facades\Route;
use Session;
use Alert;
trait ImpersonateOperation
{
/**
* Define which routes are needed for this operation.
*
* @param string $segment Name of the current entity (singular). Used as first URL segment.
* @param string $routeName Prefix of the route name.
* @param string $controller Name of the current CrudController.
*/
protected function setupImpersonateRoutes($segment, $routeName, $controller)
{
Route::get($segment.'/{id}/impersonate', [
'as' => $routeName.'.impersonate',
'uses' => $controller.'@impersonate',
'operation' => 'impersonate',
]);
}
/**
* Add the default settings, buttons, etc that this operation needs.
*/
protected function setupImpersonateDefaults()
{
$this->crud->allowAccess('impersonate');
$this->crud->operation('impersonate', function () {
$this->crud->loadDefaultOperationSettingsFromConfig();
});
$this->crud->operation('list', function () {
$this->crud->addButton('line', 'impersonate', 'view', 'crud::buttons.impersonate');
});
}
/**
* Impersonate that user and redirect to his profile.
*
* @return Response
*/
public function impersonate()
{
$this->crud->hasAccessOrFail('impersonate');
$entry = $this->crud->getCurrentEntry();
backpack_user()->setImpersonating($entry->id);
Alert::success('Impersonating '.$entry->name.' (id '.$entry->id.').')->flash();
// load the view
return redirect('getting-started');
}
}
resources/views/vendor/backpack/crud/buttons/impersonate.blade.php
:@if ($crud->hasAccess('impersonate'))
<a href="{{ url($crud->route.'/'.$entry->getKey().'/impersonate') }} " class="btn btn-sm btn-link {{ backpack_user()->id == $entry->getKey()? 'disabled': '' }}"><i class="fa fa-user"></i> Impersonate</a>
@endif
app/Http/Middleware/Impersonate.php
:<?php
namespace App\Http\Middleware;
use Closure;
class Impersonate
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->session()->has('impersonate') && backpack_user()->hasRole('superadmin')) {
backpack_auth()->onceUsingId($request->session()->get('impersonate'));
}
return $next($request);
}
}
Notice above we've also checked that the admin has a superadmin role (to only allow them to impersonate users). You might wish to change that to a permission, or restrict it based on ID to only allow a few admins to impersonate other users.
app\Http\Kernel.php
's $routeMiddleware array:
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
//...
'impersonate' => \App\Http\Middleware\Impersonate::class,
];
auth
middleware inside routes/web.php
- you can now just use the impersonate
middleware along with auth
. Alternatively, if you want ALL routes to have the impersonate feature, you could add this middleware inside your app/Http/Kernel.php
's $middlewareGroups, under web
.That's it. It wasn't such a difficult feature to build, was it? Keep in mind this is a functionality that few admin panels have, and now - you have it :-)
In the process we've:
Thanks for reading & following. Cheers!
Subscribe to our "Article Digest". We'll send you a list of the new articles, every week, month or quarter - your choice.
What do you think about this?
Wondering what our community has been up to?