在 Orchid 中,访问控制是通过权限角色来管理的。权限定义了访问权限,可以直接分配给用户或通过角色分配,从而简化访问管理。

通常,使用角色来分组权限会更好,因为这使得用户权限管理更简单。与其为每个用户分配单独的权限,不如通过角色为用户分配一个或多个角色。然而,如果需要,也可以直接将权限分配给用户。

重要提示: 权限并不替代 Laravel 的 GatePolicies 机制。这些机制仍然是细粒度访问控制所必需的,权限与它们一起工作。

尽管角色简化了管理,重点应放在权限上。应用程序逻辑应基于权限而不是角色来检查访问,使用 can 方法。

重要提示: 访问应始终通过权限进行检查,而不是角色。角色只是用于分组权限的便利,访问应始终基于权限而不是角色进行检查。

用法

方法 hasAccess 将严格要求传递的权限有效以授予访问权限。

// 检查同时针对用户及其角色进行
Auth::user()->hasAccess($string);

方法 hasAnyAccess 将在任何权限通过检查时授予访问权限。

$user = User::find(1);

if ($user->hasAnyAccess(['user.admin', 'user.update'])) {
    // 如果用户有权限,则执行此代码
}

注意。 可以使用通配符基于权限进行检查,使用 * 字符匹配任何权限集合。

$user = User::find(1);

if ($user->hasAccess('user.*')) {
    // 如果用户有权限,则执行此代码
}

在少数情况下,您可能需要获取直接或通过角色拥有权限的用户。为此,您可以使用:

User::byAccess('platform.systems.users')->get();

// 或者如果用户至少有一个传递的权限
User::byAnyAccess([
   'platform.systems.users',
   'non existent',
])->get();

用户有多种管理角色的选项:

// 获取所有用户角色
Auth::user()->getRoles();

// 检查用户是否有角色
Auth::user()->inRole($role);

// 为用户添加角色
Auth::user()->addRole($role);

角色

角色也有以下程序:

// 返回具有此角色的所有用户。
$role->getUsers();

注册权限

您可以在应用程序中注册权限以管理对特定功能的访问。

使用提供者注册权限的示例:

use Orchid\Platform\ItemPermission;
use Orchid\Platform\OrchidServiceProvider;

class PermissionServiceProvider extends OrchidServiceProvider
{
    /**
     * 为应用程序注册权限。
     *
     * @return ItemPermission[]
     */
    public function permissions(): array
    {
        return [
            ItemPermission::group('modules')
                ->addPermission('analytics', '访问数据分析')
                ->addPermission('monitor', '访问系统监控'),
        ];
    }
}

屏幕中的检查

每个创建的屏幕已经使用方法 permission 设置了内置的权限检查,该方法接受数组和字符串值进行验证:

namespace App\Orchid\Screens;

use Orchid\Screen\Screen;

class History extends Screen
{
    /**
     * 访问此屏幕所需的权限。
     */
    public function permission(): ?iterable
    {
        return [
            'systems.history'
        ];
    }
        
    // ...
}

如果列出了多个键,用户只要有至少一个权限就会被授予访问权限。

如果没有访问权限,将调用静态方法 unaccessed,默认情况下将显示 403 错误。您可以重写此响应,例如重定向到支付页面或返回不同的响应:

use Illuminate\Http\RedirectResponse;

/**
 * @return \Illuminate\Http\RedirectResponse
 */
public static function unaccessed(): RedirectResponse
{
    return redirect('/other-screen');
}

中间件中的检查

小型应用程序可能不需要为每个屏幕或类定义权限,而是检查它们在路由中的可用性。 为此,在 app/Http/Kernel 中注册一个新的 middleware

/**
 * 应用程序的路由中间件。
 *
 * 这些中间件可以分配给组或单独使用。
 *
 * @var array
 */
protected $routeMiddleware = [
    //...
    'access' => \Orchid\Platform\Http\Middleware\Access::class,
];

之后,可以将其用于任何路由定义,通过传递参数 access:my-permission,就像在 Auth::user()->hasAccess($string); 中一样。

Route::screen('/stories', StoriesScreen::class)
    ->middleware('access:systems.history');

您还可以将它们分组到组中:

Route::middleware(['access:systems.history'])->group(function () {
    Route::screen('/stories', StoriesScreen::class);
    Route::get('/stories/best', function () {
        // ...
    });
});

Blade 中的检查

对于依赖于 Blade 模板渲染的应用程序,可以方便地添加“自定义 If 语句”如下:

use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Auth;

/**
 * 启动任何应用程序服务。
 *
 * @return void
 */
public function boot()
{
    Blade::if('hasAccess', function (string $value) {
        $user = Auth::user();

        if ($user === null) {
            return false;
        }

        return $user->hasAccess($value);
    });
}

一旦定义了自定义条件,您可以在模板中使用它:

@hasAccess('platform.index')
    <!-- 用户有 'platform.index' 操作的权限 -->
@elsehasAccess('platform.other')
    <!-- 用户没有 'platform.index' 的权限,
         但有 'platform.other' 的权限 -->
@else
    <!-- 用户没有 'platform.index'
         和 'platform.other' 的权限 -->
@endhasAccess

@unlesshasAccess('platform.index')
    <!-- 用户没有 'platform.index' 的权限 -->
@endhasAccess

通过控制台创建管理员用户

要创建具有最大(在创建时)权限的用户,请运行以下命令:

php artisan orchid:admin

要为现有用户授予最大权限,请使用 --id 选项运行:

php artisan orchid:admin --id=1

如果您为用户添加了新的必填列并需要修改命令以添加相应的值,请首先通过在服务提供者中添加以下代码指定 Orchid 使用您的模型:

use Orchid\Support\Facades\Dashboard;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Dashboard::useModel(
            \Orchid\Platform\Models\User::class,
            \App\Models\User::class
        );
    }
}

然后在您的 User 模型中重写 createAdmin 方法:

public static function createAdmin(string $name, string $email, string $password): void
{
    throw_if(static::where('email', $email)->exists(), '用户已存在');

    static::create([
        'name'        => $name,
        'email'       => $email,
        'password'    => Hash::make($password),
        'permissions' => Dashboard::getAllowAllPermission(),
    ]);
}

现在您可以根据需要修改此方法,并在执行创建命令时将执行此方法。

用户模拟

Orchid\Access\Impersonation 类为开发人员提供了方便的功能,可以以其他用户身份登录。 它允许管理员模拟其他用户,以便查看和执行他们的操作。 这对于解决用户报告的问题非常有用。

要切换到其他用户,请使用 loginAs() 方法:

use Orchid\Access\Impersonation;

// 以其他用户身份登录
Impersonation::loginAs($otherUser);

要返回到原始用户,请调用 logout() 方法:

// 返回到原始用户
Impersonation::logout();

isImpersonating() 方法检查是否已进行模拟:

if (Impersonation::isImpersonating()) {
    // 用户正在模拟其他用户
}

impersonator() 方法返回有关原始用户的信息。如果没有进行模拟,该方法将返回 null

// 获取有关原始用户的信息
$impersonator = Impersonation::impersonator();

我们的朋友