logo

模拟用户

概述

将应用程序部署到生产环境后,你可能偶尔需要「模拟」应用程序的另一个用户,以调试客户报告的问题。值得庆幸的是,Nova 包含处理这种情况的内置功能。

启用模拟用户功能

要启用模拟用户功能,请在应用程序的 User 模型中添加 Laravel\Nova\Auth\Impersonatable 特性:

php
<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Nova\Auth\Impersonatable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Impersonatable, Notifiable;

    // ...
}

一旦将 Impersonatable 特性添加到应用程序的 User 模型中,「模拟用户」操作将可通过相应资源的内联操作菜单使用:

Impersonation

定制模拟用户授权

默认情况下,任何有权限查看 Nova 面板的用户都可以模拟任何其他用户。不过,你可以通过在应用程序的 Impersonatable 模型上定义 canImpersonatecanBeImpersonated 方法,自定义谁可以模拟其他用户以及哪些用户可以被模拟:

php
use Illuminate\Support\Facades\Gate;

/**
 * 确定用户是否可以模拟其他用户。
 *
 * @return bool
 */
public function canImpersonate()
{
    return Gate::forUser($this)->check('viewNova');
}

/**
 *  确定用户是否可以被模拟。
 *
 * @return bool
 */
public function canBeImpersonated()
{
    return true;
}

检查模拟状态

通过 Laravel 的服务容器解析 Laravel/Nova\Contracts\ImpersonatesUsers 接口的实现,就可以检查应用程序当前的模拟状态:

php
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Laravel\Nova\Contracts\ImpersonatesUsers;

Route::get('/impersonation', function (Request $request, ImpersonatesUsers $impersonator) {
    if ($impersonator->impersonating($request)) {
        $impersonator->stopImpersonating($request, Auth::guard(), User::class);
    }
});

模拟事件

默认情况下,你可以通过使用模拟的可用事件来添加额外的自定义功能:

  • Laravel\Nova\Events\StartedImpersonating
  • Laravel\Nova\Events\StoppedImpersonating

例如,你可能希望记录模拟事件,你可以在应用程序的 EventServiceProviderboot 方法中为这些事件注册监听器:

php
use Illuminate\Support\Facades\Event;
use Laravel\Nova\Events\StartedImpersonating;
use Laravel\Nova\Events\StoppedImpersonating;

Event::listen(StartedImpersonating::class, function ($event) {
    logger("User {$event->impersonator->name} started impersonating {$event->impersonated->name}");
});

Event::listen(StoppedImpersonating::class, function ($event) {
    logger("User {$event->impersonator->name} stopped impersonating {$event->impersonated->name}");
});