soyhuce/laravel-fluent-policy

在 Laravel 中编写流畅的策略

1.6.0 2024-03-08 15:30 UTC

README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status GitHub PHPStan Action Status Total Downloads

在 Laravel 中流畅地编写您的策略。

<?php

class PostPolicy extends FluentPolicy
{
    public function delete(User $user, Post $post): Response
    {
        return $this->denyWhen($post->user_id !== $user->id)
            ->denyWhen($post->published_at !== null)
            ->allow();
    }
}

安装

您可以通过 composer 安装此包

composer require soyhuce/laravel-fluent-policy

使用方法

此包的目的是使您能够更容易地以干净的语法编写策略。

例如,以下策略

<?php
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
    use HandlesAuthorization;

    public function delete(User $user, Post $post): bool
    {
        if ($post->user_id !== $user->id) {
            return false;
        }
        
        if ($post->published_at !== null) {
            return false;
        }
    
        return true;
    }
}

可以重写为

<?php
use Illuminate\Auth\Access\Response;
use Soyhuce\FluentPolicy\FluentPolicy;

class PostPolicy extends FluentPolicy
{
    public function delete(User $user, Post $post): Response
    {
         return $this->denyWhen($post->user_id !== $user->id)
            ->denyWhen($post->published_at !== null)
            ->allow();
    }
}

如果需要,您可以自定义响应

return $this->denyWhen($post->published_at !== null, 'You cannot delete a published post')
    ->allow();

您也可以这样调用另一个策略或门控

return $this->authorize($user, 'update', $post)
    ->allowWhen($post->published_at === null)
    ->deny();

自定义 HTTP 状态

您可以通过返回自定义 HTTP 状态码来拒绝策略

return $this->denyWithStatusWhen($post->user_id !== $user->id, 404)
        ->allow();
// or $this->>allowWhen(...)->denyWithStatus(404);

404 状态码的情况下,您可以使用快捷方式

return $this->denyAsNotFoundWhen($post->user_id !== $user->id)
        ->allow();
// or $this->>allowWhen(...)->denyAsNotFound();

懒加载评估

不同的分支 allowWhendenyWhen 是懒加载评估的,这意味着以下代码是完全正确的

<?php
use Illuminate\Auth\Access\Response;
use Soyhuce\FluentPolicy\FluentPolicy;

class PostPolicy extends FluentPolicy
{
    public function delete(User $user, Post $post): Response
    {
         // Here, $post->published_at is Carbon or null
    
         return $this->denyWhen($post->user_id !== $user->id)
            ->allowWhen($post->published_at === null) // 1
            ->allowWhen($post->published_at->isFuture()) // 2
            ->deny();
    }
}

2 只有在之前的分支都为假时才会调用。我们通过 1 确保这里 $post->published_at 不是 null。

PHPStan

当在

public function delete(User $user, Post $post): Response
{
     return $this->denyWhen($post->user_id !== $user->id)
        ->allowWhen($post->published_at === null) // 1
        ->allowWhen($post->published_at->isFuture()) // 2
        ->deny();
}

上运行 PHPStan 时

2 上抛出错误(Cannot call method isFuture on Carbon|null)。

includes:
    - vendor/bin/soyhuce/laravel-fluent-policies/extension.neon

遗憾的是,由于 PHPStan 的限制,您仍然需要稍微重写您的策略

public function delete(User $user, Post $post): Response
{
    $this->denyWhen($post->user_id !== $user->id)
        ->allowWhen($post->published_at === null);
    // From here, PHPStan understands that $post->published_at is not null
    
    return $this->allowWhen($post->published_at->isFuture())
        ->deny();
}

测试

composer test

变更日志

请参阅 CHANGELOG 了解最近更改的更多信息。

贡献

请参阅 CONTRIBUTING 了解详细信息。

安全漏洞

请查看我们如何报告安全漏洞的 安全策略

鸣谢

许可

MIT 许可证(MIT)。请参阅 许可文件 了解更多信息。