-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Laravel Nova does not respect nova-impersonate guard config #6796
Comments
Please provide full reproducing repository based on fresh installation as suggested in the bug report template (or you can refer to https://github.com/nova-issues for example) |
Please see https://github.com/steffanhalv/laravel-config-bug for how laravel always prioritize the 'web' guard. As for the Laravel Nova bug the problem should be very simple to see based on this: vendor/laravel/nova/src/Auth/Adapters/SessionImpersonator.php // The $guard inserted here will always be the 'web' guard from Laravel 11 and up because it is always added to the top of the config
public function impersonate(Request $request, StatefulGuard $guard, Authenticatable $user)
{
return rescue(function () use ($request, $guard, $user) {
$impersonator = Nova::user($request);
$request->session()->put(
'nova_impersonated_by', $impersonator->getAuthIdentifier()
);
$request->session()->put(
'nova_impersonated_remember', $guard->viaRemember()
);
$novaGuard = config('nova.guard') ?? config('auth.defaults.guard');
$authGuard = method_exists($guard, 'getName')
? Str::between($guard->getName(), 'login_', '_'.sha1(get_class($guard)))
: null;
if (is_null($authGuard)) {
return false;
}
\Log::info('$novaGuard ' . $novaGuard . ' $authGuard ' . $authGuard);
if ($novaGuard !== $authGuard) {
$request->session()->put(
'nova_impersonated_guard', $authGuard
);
}
$guard->login($user);
event(new StartedImpersonating($impersonator, $user));
return true;
}, false);
} Also see how |
Work aroundCreate a new controllerapp/Http/Controllers/Nova/ImpersonateController.php <?php
namespace App\Http\Controllers\Nova;
use Illuminate\Support\Facades\Auth;
use Laravel\Nova\Http\Controllers\ImpersonateController as NovaImpersonateController;
use Laravel\Nova\Contracts\ImpersonatesUsers;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Nova;
use Laravel\Nova\Util;
/**
* This Controller overrides NovaImpersonateController to provide the correct auth guard.
* @see: https://github.com/laravel/nova-issues/issues/6796
*/
class ImpersonateController extends NovaImpersonateController
{
/**
* Start impersonating a user.
*
* @param \Laravel\Nova\Http\Requests\NovaRequest $request
* @param \Laravel\Nova\Contracts\ImpersonatesUsers $impersonator
* @return \Illuminate\Http\JsonResponse
*/
public function startImpersonating(NovaRequest $request, ImpersonatesUsers $impersonator)
{
if ($impersonator->impersonating($request)) {
return $this->stopImpersonating($request, $impersonator);
}
/** @var class-string<\Illuminate\Contracts\Auth\Authenticatable&\Illuminate\Database\Eloquent\Model> $userModel */
$userModel = with(Nova::modelInstanceForKey($request->input('resource')), function ($model) {
return ! is_null($model) ? get_class($model) : Util::userModel();
});
// @notice - Obtaining auth guard by nova config as Util resolves to wrong auth guard
$authGuard = config('nova-impersonate.default_impersonator_guard'); // Util::sessionAuthGuardForModel($userModel);
$currentUser = Nova::user($request);
/** @var \Illuminate\Contracts\Auth\Authenticatable&\Illuminate\Database\Eloquent\Model $user */
$user = $userModel::findOrFail($request->input('resourceId'));
// Now that we're guaranteed to be a 'real' user, we'll make sure we're
// actually trying to impersonate someone besides ourselves, as that
// would be unnecessary.
if (! $currentUser->is($user)) {
abort_unless(optional($currentUser)->canImpersonate() ?? false, 403);
abort_unless(optional($user)->canBeImpersonated() ?? false, 403);
$impersonator->impersonate(
$request,
Auth::guard($authGuard),
$user
);
}
return $impersonator->redirectAfterStartingImpersonation($request);
}
} & overwrite the routeapp/Providers/NovaServiceProvider.php use App\Http\Controllers\Nova\ImpersonateController;
class NovaServiceProvider extends NovaApplicationServiceProvider
{
/**
* Register the Nova routes.
*/
protected function routes(): void
{
Nova::routes()
->withAuthenticationRoutes(default: true)
->withPasswordResetRoutes()
->register();
Route::middleware(['nova'])->post('/nova-api/impersonate', [ImpersonateController::class, 'startImpersonating'])->name('nova-api.start-nova-impersonation');
} |
Okay, but how does that affect your application since both |
They do have the same driver and provider but different logic and purpose. And because laravel nova automatically always select the web guard for impersonation while we are using the nova guard for our nova dashboard, impersonation does not work. |
Please show the different in logic in the reproduction repository for further debug. As of now, it doesn't show any difference and shouldn't matter |
I don’t think it would be helpful to showcase our custom logic within our custom Nova guard. The issue is not with our implementation but rather with the fact that we have explicitly configured Nova Impersonate to use our nova guard in config/nova-impersonate.php by setting: 'default_impersonator_guard' => 'nova', However, during impersonation, it still uses the web guard instead, which prevents impersonation from working as expected. I believe the problem has been clearly explained above, especially when considering the workaround we implemented and the files I referenced. Additionally, while the Laravel issue you closed as a duplicate is related, it is not quite the same problem, I posted a new comment there also laravel/framework#55165. At this point, I don’t think setting up a full reproduction repository is necessary, given that we have a workaround. However, the current solution is not ideal, and I still believe this is a bug that needs to be addressed. Anyways, thanks for your time — I appreciate your help in looking into this :-) |
This is not a Laravel Nova feature. Again, there is nothing here that indicates that the |
Uh, thx, that explains something. It must have been picked up from this repo KABBOUCHI/nova-impersonate#58 ... at some time. Still, I can't get the impersonation to work without my work around for some reason, and in laravel 10 it worked because laravel did respect the order of which guards were defined, but now it does not because the 'web' guard is always moved to index 0. I also tried to remove the nova session guard and only use the web auth guard for session authentication, but now it complains about not finding the nova guard. Guess I have to investigate some more on this. Thx for your help. |
Description:
Laravel Nova does not respect nova-impersonate guard config when multiple guards using same provider and driver.
Detailed steps to reproduce the issue on a fresh Nova installation:
config/nova-impersonate.php
Notice: In laravel < 10 this would work as Laravel Nova selects the first defined guard, but in laravel 11 the web guard is always added to the top
Related Laravel issue: laravel/framework#55165
config/auth.php
The authGuard will always resolve to 'web' from Laravel 11 and up ...
vendor/laravel/nova/src/Http/Controllers/ImpersonateController.php
Because this looks for the first guard having the given driver and provider (which always will be 'web' in >= Laravel 11)
vendor/laravel/nova/src/Util.php
Solution
Always respect the
default_impersonator_guard
config.The text was updated successfully, but these errors were encountered: