renoki-co/laravel-acl

为 Laravel 应用程序提供的简单、AWS IAM 风格的 ACL,利用强大的声明在应用程序中实现细粒度权限。

dev-master 2022-12-16 07:23 UTC

README

CI codecov StyleCI Latest Stable Version Total Downloads Monthly Downloads License

简单、AWS IAM 风格的 Laravel 应用程序 ACL,利用强大的声明在应用程序中实现细粒度权限。 🔐

🚀 安装

您可以通过 composer 安装此包

composer require renoki-co/laravel-acl

发布配置

php artisan vendor:publish --provider="RenokiCo\LaravelAcl\LaravelAclServiceProvider" --tag="config"

发布迁移

php artisan vendor:publish --provider="RenokiCo\LaravelAcl\LaravelAclServiceProvider" --tag="migrations"

🙌 使用方法

此包基于 renoki-co/acl,但利用 Laravel 环境快速设置权限。

如果您熟悉如何使用 ARNs策略,现在您可以使用相同的语法来定义和检查您的 ACL 策略。

您可以查看更多 IAM 示例 来了解如何定义您的策略。

ACL 系统的作用是为可以执行一组资源上特定操作的特定实体分配策略或规则/声明,以便以后在整个应用程序中验证它们。

在 Laravel 中,行动者类通常是可验证的模型。要设置行动者类,您必须使用 HasPolicies 特性对其进行扩展

use RenokiCo\LaravelAcl\Concerns\HasPolicies;
use RenokiCo\LaravelAcl\Contracts\RuledByPolicies;
// ...

class User extends Authenticatable implements RuledByPolicies
{
    use HasPolicies;

    // ...
}

每当您需要行动者检查权限时,该包将自动获取附加的权限。要附加策略,只需定义一个静态 AclPolicy 并将其直接附加到行动者,并指定一个自定义名称(这可能有助于识别特定的附加项)

use RenokiCo\Acl\Acl;
use RenokiCo\Acl\Statement;

$policy = Acl::createPolicy([
    Statement::make(
        effect: 'Allow',
        action: 'server:List',
        resource: [
            'arn:php:default:local:123:server',
        ],
    ),
]);

$user = Auth::user();

// Do this once, as it stores the policy in the database, in relation to the user.
$user->attachPolicy('ListServers', $policy);

$user->isAllowedTo(
    'server:List',
    'arn:php:default:local:123:server',
); // true

🧬 ARNables

此文档部分可能已过时,并经过调整以表示此特定用例。请考虑 阅读 ACL 文档,同时考虑到当前指南。

PHP 更为面向对象。ARNables 可以帮助将您的模型或类转换为 ARNs 的简化版本,这样您就不必每次都编写所有 ARNs,而是将它们传递给 isAllowedTo() 方法,根据它是一个资源无关的 ARN,还是一个指向特定资源的 ARN。

资源无关 ARN 与资源 ARN

资源无关 ARN 适用于 list 或 create 等操作。它们不指向特定资源,而是指向该资源的“通用”权限,这可以允许列出或创建资源。例如,arn:php:default:local:123:server

资源 ARN 指向特定资源的 ARN。例如,deletemodify 等操作是使用这些 ARN 的好例子。例如,arn:php:default:local:123:server/1arn:php:default:local:123:backup/1

解析区域和帐户 ID

让我们以这个 ARN 示例为例:arn:php:default:local:123:server

由于此 ARN 无关资源,无法在没有两个关键组件的情况下将 Server 类正确转换为 ARN

  • 区域,在这种情况下为 local
  • 帐户 ID,在这种情况下为 123

虽然这些值有默认值,但您必须让 ACL 服务知道这些值的正确值。

对于这些值,您可以参考AWS的示例:它允许您选择区域(在控制台中:通过右上角的选择器手动更改区域;在API中:通过指定--region参数),并且您必须对账户进行认证,在这种情况下,您当前的登录会话知道您的账户ID。

在模型中解决

任何具有HasPolicies特性的角色已将区域解析为local,并将账户ID作为主键。最佳做法是根据当前请求会话覆盖区域解析器,例如

class User extends Authenticatable implements RuledByPolicies
{
    use HasPolicies;

    /**
     * Resolve the account ID of the current actor.
     * This value will be used in ARNs for ARNable static instances,
     * to see if the current actor can perform ID-agnostic resource actions.
     *
     * @return null|string|int
     */
    public function resolveArnAccountId()
    {
        return $this->getKey();
    }

    /**
     * Resolve the region of the current actor.
     * This value will be used in ARNs for ARNable static instances,
     * to see if the current actor can perform ID-agnostic resource actions.
     *
     * @return null|string|int
     */
    public function resolveArnRegion()
    {
        return session('region', 'local');
    }
}

// i.e. Handle region change via HTTP requests
public function changeRegion(Request $request)
{
    $data = $request->validate([
        'region' => ['required', 'string', 'in:us-east-1,eu-central-1'],
    ]);

    session(['region' => $data['region']]);

    return redirect('/');
}

使用ARNables与角色一起使用

假设您有一个名为Server的模型实例,它属于一个用户

use RenokiCo\LaravelAcl\Concerns\HasArn;
use RenokiCo\LaravelAcl\Contracts\Arnable;
use RenokiCo\LaravelAcl\BuildResourceArn;

class Server extends Model implements Arnable
{
    use HasArn;

    protected $fillable = [
        'user_id',
        'name',
        'ip',
    ];

    public function arnResourceAccountId()
    {
        return $this->user_id;
    }
}

现在,您可以通过传递服务器类名称而不是传递完整的ARN到->isAllowedTo方法

$policy = Acl::createPolicy([
    Statement::make(
        effect: 'Allow',
        action: 'server:List',
        resource: [
            'arn:php:default:local:123:server',
        ],
    ),
    Statement::make(
        effect: 'Allow',
        action: 'server:Delete',
        resource: [
            'arn:php:default:local:123:server/1',
        ],
    ),
]);

$user = Auth::user();

$user->isAllowedTo('server:List', Server::class); // true

要检查特定资源ARN的权限,您可以将对象本身传递给ARN参数

$server = Server::find('1');
$user->isAllowedTo('server:Delete', $server); // true

如您之前所见,在角色模型中,您可以指定它们的账户标识符。在ARN如arn:php:default:local:123:server中,123部分是账户ID或账户标识符。因此,将resolveArnAccountId设置为返回123,策略将允许角色在该特定资源上执行server:List操作。

资源ID会自动解析为模型的主键,但您可以覆盖它

class Server extends Model implements Arnable
{
    use HasArn;

    public function arnResourceId()
    {
        return $this->getKey();
    }
}

使用ARNables与团队一起使用

在更复杂的层面上,拥有一个将更多角色组合在一起的模型,如Team拥有更多User,相当常见,尤其是如果您在使用Laravel Jetstream

您仍然需要在用户级别实现策略检查,但关于将“账户ID”解析为更类似于团队ID,只要资源是在Team下创建的。

class Team extends Model
{
    //
}
use RenokiCo\LaravelAcl\Concerns\HasPolicies;
use RenokiCo\LaravelAcl\Contracts\RuledByPolicies;

class User extends Authenticatable implements RuledByPolicies
{
    use HasPolicies;

    public function resolveArnAccountId()
    {
        return $this->current_team_id;
    }
}

在ARNables的情况下,它们的模型应该解析团队的账户ID

class Server extends Model implements Arnable
{
    use HasArn;

    public function arnResourceAccountId()
    {
        return $this->team_id;
    }
}

更多资源

🐛 测试

vendor/bin/phpunit

🤝 贡献

有关详细信息,请参阅CONTRIBUTING

🔒 安全性

如果您发现任何与安全相关的问题,请通过电子邮件alex@renoki.org而不是使用问题跟踪器。

🎉 致谢