技術社區

不使用三方包時,如何在ThinkSNS中建立優雅的用戶權限管理
admin | 發表于: 2017-12-21 回答

需求場景

就是用戶組+權限節點,這個需求 laravel 有很多很好的第三方包實現。下面描述代碼不參與緩存機制純數據庫查詢,給大家提供一個思路。

下面的代碼都是來自于ThinkSNS+,是基于 Laravel 全新開發的 ThinkSNS 社交開源項目,遵循 Apache2.0 開源協議。歡迎 Star 哦。

數據表設計

其實這一塊我個人是參考的 Zizaco/entrust 因為我覺得,大多數情況下,我們要用的角色和權限節點都是真多用戶的。數據表設計如下:

h7SGVm84q9.png

可以看到關系如下 user > role > ability ,其中關系全部都是多對多關系。一個用戶可以擁有多個 role,一個 ability 可以被分配給多個 role 。

鏈式方法設計

$user>ability('create user'); // 判斷是否有 create user 權限。
$user>ability('owner', 'delete user'); // 判斷用戶是否擁有 owner 用戶組,且是否這個組擁有 delete user 權限。
$user>ability(); // 返回一個 Ability 實例。
$user>roles;  // 讀取用戶所擁有的所有用戶組。
$user>roles(); // 獲取 Builder 實例。
$user>roles('owner'); // 檢查用戶是否擁有 owner 用戶組,擁有返回 model 實例,否則返回 false。
$user>ability()>roles(); // 讀取用戶所擁有的所有用戶組。返回的是一個 集合??捎眉纤蟹椒?。
$user>ability()>roles('owner'); // 檢查用戶是否擁有 owner 用戶組,擁有返回 model 實例,否則返回 false。
$user>ability()>all(); // 返回用戶擁有的所有權限集合。
$user>ability()>all('create user'); // 檢查用戶是否擁有 create user 權限,沒有返回 false ,有返回 ability 實例。

其中調用 $user>ability()>all() 和 $user>ability()>all() 都是返回的 集合 可以鏈式調用集合下的所有方法進一步操作。

ability 用戶 Trait

    /
    public function ability(...$parameters)
    {
        if (isset($parameters[1])) {
            return ($role = $this>resolveAbility()>roels($parameters[0]))
                ? $role>ability($parameters[1])
                : false;
        } elseif (isset($parameters[0])) {
            return $this>resolveAbility()
                >all($parameters[0]);
        }

        return $this>resolveAbility();
    }

    /
      The user all roles.
     
      @param string $role
      @return mied
      @author Seven Du 
     /
    public function roles(string $role = '')
    {
        if ($role) {
            return $this>ability()>roles($role);
        }

        return $this>belongsToMany(Role::class, 'role_user', 'user_id', 'role_id');
    }

    /
      Resolve ability service.
     
      @return hiyiPlusServicesUserAbility
      @author Seven Du 
     /
    protected function resolveAbility()
    {
        if (! ($this>ability instanceof UserAbility)) {
            $this>ability = new UserAbility();
        }

        return $this>ability>setUser($this);
    }
}

Ability 實例

    /
    public function roles(string $role = '')
    {
        $roles = $this>user()
            >roles()
            >get()
            >keyBy('name');

        if (! $role) {
            return $roles;
        }

        return $roles>get($role, false);
    }
    /
      Get all abilities or get first ability.
     
      @param string $ability
      @return mixed
      @author Seven Du 
     /
    public function all(string $ability = '')
    {
        $roles = $this>roles();
        $roles>load('abilities');
        $abilities = $roles>reduce(function ($collect, $role) {
            return $collect>merge(
                $role>abilities>keyBy('name')
            );
        }, new Collection());

        if (! $ability) {
            return $abilities;
        }

        return $abilities>get($ability, false);
    }
    /
      Get user instance.
     
      @return hiyiPlusModelsUser
      @author Seven Du 
     /
    public function user(): UserModel
    {
        return $this>user;
    }
    /
      Set user model.
     
      @param hiyiPlusModelsUser $user
      @author Seven Du 
     /
    public function setUser(UserModel $user)
    {
        $this>user = $user;
        return $this;
    }
}

Role 模型所需代碼

    /
    public function abilities()
    {
        return $this>belongsToMany(Ability::class, 'ability_role', 'role_id', 'ability_id');
    }
    /
      Get or check The role ability.
     
      @param string $ability
      @return false|UserPlusModelsAbility
      @author Seven Du 
     /
    public function ability(string $ability)
    {
        return $this>abilities>keyBy('name')>get($ability, false);
    }
}

使用

然后我們打開 User 模型wen jia文件添加如下代碼:

class User ...
{
    use UserHasAbility;
}

總結

其實性狀在 User 模型中只暴露了 roles 和 ability 兩個公開方法。但是已經足以勝任用戶組權限判斷邏輯了。

整個 ability 都是結合在集合之上的一些封裝,這樣是的代碼調用更加優雅。

以上代碼是在開發ThinkSNS+中的實際真實代碼。具體的實現可參考項目。

以上代碼都來自于ThinkSNS Plus,看完整的開發代碼可以看倉庫:

GitHub: https://github.com/slimkit/thinksnsplus(開源不易,求 Star )

回復列表

請先登錄,登錄后回復!

登錄 注冊
3d专家预测组三组六方法 江苏快3遗漏号码对照表 北京十一选五走势图彩经网 辽宁福彩快乐12走势图前三直 鼎牛配资 广东好彩1怎么玩 资产配置型私募基金 青海快三电脑版 深圳风采开奖结果查询果 河北十一选五前三走势 10bet在线娱乐城百家乐