检查和验证复杂的特定用户权限。

1.0 2021-04-28 22:18 UTC

This package is auto-updated.

Last update: 2024-09-29 05:36:36 UTC


README

有助于检查复杂的用户权限。

灵感来源于 Symfony 投票系统

安装

$ composer require thomas-miceli/voters

使用

要检查用户动作(例如查看或编辑)的特定权限 $attribute(例如文章),无论是否有 $subject(例如文章),每个注册的投票者都会被调用,并检查他们是否可以对该权限进行投票。每个有资格的投票者都会投票决定用户是否可以拥有该权限。

为我们的博客设置权限。

创建权限对象

<?php 

$permission = new \ThomasMiceli\Voter\Permission;
$permission->addVoter(new ArticleVoter); // register the voter for this permission object
$user = ...
$article = ...

$permission->can($user, ArticleVoter::VIEW, $article); // check if our user can view the article
$permission->can($user, ArticleVoter::EDIT, $article); // check if our user can edit the article

创建投票者

<?php

/* This voter determine what the user can do with an article from our blog. */
class ArticleVoter implements \ThomasMiceli\Voter\Voter
{

    const VIEW = 'view';
    const EDIT = 'edit';

    // if the voter can vote for the requested attribute...
    public function canVote(string $attribute, $subject = null): bool
    {
        return in_array($attribute, [self::EDIT, self::VIEW]) && $subject instanceof Article;
    }

    // ...if yes, the voter will determinate and return the permission for this attribute
    public function vote(?\ThomasMiceli\Voter\VoterUser $user, string $attribute, $subject = null): bool
    {
        /** @var Article $subject */
        switch ($attribute) {
            // if the user is connected, he can read the article
            case self::VIEW: return $user !== null; 
            
            // if the user is the author, he can modify the article
            case self::EDIT: return $subject->getAuthor() === $user;
        }
        
        // the user has not the permission for other attributes
        return false;
    }
}

策略

当多个投票者有资格对属性进行投票时,可以设置不同的策略来决定权限。

<?php

$permission = new \ThomasMiceli\Voter\Permission(new \ThomasMiceli\Voter\Strategy\AffirmativeStrategy); // default strategy
// $permission::can() returns true if at least one of the registered voters approved the attribute

$permission = new \ThomasMiceli\Voter\Permission(new \ThomasMiceli\Voter\Strategy\VetoStrategy);
// $permission::can() returns true if all the registered voters approved the attribute

$permission = new \ThomasMiceli\Voter\Permission(new \ThomasMiceli\Voter\Strategy\MajorityStrategy);
// $permission::can() returns true if at least half plus one of the registered voters approved the attribute

我们可以使用工厂静态方法以获得更好的可读性。

<?php

$permission = \ThomasMiceli\Voter\Permission::affirmative();
$permission = \ThomasMiceli\Voter\Permission::veto();
$permission = \ThomasMiceli\Voter\Permission::majority();

我们可以创建自己的策略,并将其设置到权限中...

<?php

class CustomStrategy implements \ThomasMiceli\Voter\Strategy\VoterStrategy {
    
    // the permission is granted if at least 4 voters voted true for an attribute
    public function can(?\ThomasMiceli\Voter\VoterUser $user, array $voters, string $attribute, $subject): bool
    {
        $approvals = 0;
        foreach ($voters as $voter) {
            if ($voter->canVote($attribute, $subject)) {
                $vote = $voter->vote($user, $attribute, $subject);
                //ConsoleLogger::debug($voter, $vote, $attribute, $user, $subject);

                if ($vote) {
                    ++$approvals;
                }
            }
        }
        return $approvals > 3;
    }
}

...然后使用它。

<?php

$permission = new \ThomasMiceli\Voter\Permission(new CustomStrategy);

我们甚至可以轻松创建通用的投票者,允许定义应该有多少投票者批准属性。

<?php

$permission = new \ThomasMiceli\Voter\Permission(new \ThomasMiceli\Voter\Strategy\GenericStrategy(40, 5));
$permission = \ThomasMiceli\Voter\Permission::generic(40, 5);
// at least 40% and 5 voters should have approved the attribute