461
技術社區[雲棲]
不使用三方包時,如何在ThinkSNS中建立優雅的用戶權限管理
本文主要全麵講解在不適用第三方包的情況下,如何在基於Laravel框架上,研發社交係統ThinkSNS+時,簡曆一套優雅而不失性價比的用戶權限管理體係功能,【內含ThinkSNS真實代碼】。
需求場景
就是用戶組+權限節點,這個需求 laravel 有很多很好的第三方包實現。下麵描述代碼不參與緩存機製純數據庫查詢,給大家提供一個思路。
下麵的代碼都是來自於ThinkSNS+,是基於 Laravel 全新開發的 ThinkSNS 社交開源項目,遵循 Apache-2.0 開源協議。歡迎 Star 哦。
數據表設計
其實這一塊我個人是參考的 Zizaco/entrust 因為我覺得,大多數情況下,我們要用的角色和權限節點都是真多用戶的。數據表設計如下:
可以看到關係如下 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
<?php
namespace Zhiyi\Plus\Models\Concerns;
use Zhiyi\Plus\Models\Role;
use Zhiyi\Plus\Services\UserAbility;
trait UserHasAbility
{
/**
* Abiliry service instance.
*
* @var \Zhiyi\Plus\Services\UserAbility
*/
protected $ability;
/**
* User ability.
*
* @param array $parameters
* ability();
* ability($ability);
* ability($role, $ability);
* @return mixed
* @author Seven Du <shiweidu@outlook.com>
*/
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 <shiweidu@outlook.com>
*/
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 \Zhiyi\Plus\Services\UserAbility
* @author Seven Du <shiweidu@outlook.com>
*/
protected function resolveAbility()
{
if (! ($this->ability instanceof UserAbility)) {
$this->ability = new UserAbility();
}
return $this->ability->setUser($this);
}
}
Ability 實例
<?php
namespace Zhiyi\Plus\Services;
use Illuminate\Support\Collection;
use Zhiyi\Plus\Models\User as UserModel;
use Zhiyi\Plus\Contracts\Model\UserAbility as UserAbilityContract;
class UserAbility implements UserAbilityContract
{
protected $user;
/**
* Get all roles or get first role.
*
* @param string $role
* @return mixed
* @author Seven Du <shiweidu@outlook.com>
*/
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 <shiweidu@outlook.com>
*/
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 \Zhiyi\Plus\Models\User
* @author Seven Du <shiweidu@outlook.com>
*/
public function user(): UserModel
{
return $this->user;
}
/**
* Set user model.
*
* @param \Zhiyi\Plus\Models\User $user
* @author Seven Du <shiweidu@outlook.com>
*/
public function setUser(UserModel $user)
{
$this->user = $user;
return $this;
}
}
Role 模型所需代碼
<?php
namespace Zhiyi\Plus\Models;
use Illuminate\Database\Eloquent\Model;
class Role extends Model
{
/**
* Get all abilities of the role.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
* @author Seven Du shiweidu@outlook.com
/
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|\User\Plus\Models\Ability
* @author Seven Du shiweidu@outlook.com
*/
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/thinksns-plus
(開源不易,求 Star )
ThinkSNS產品免費體驗:https://www.thinksns.com/experience.html
最後更新:2017-11-03 15:04:01