不使用三方包时,如何在ThinkSNS中建立优雅的用户权限管理

简介: 本文主要全面讲解在不适用第三方包的情况下,如何在基于Laravel框架上,研发社交系统ThinkSNS+时,简历一套优雅而不失性价比的用户权限管理体系功能,【内含ThinkSNS真实代码】。 需求场景 就是用户组+权限节点,这个需求 laravel 有很多很好的第三方包实现。

本文主要全面讲解在不适用第三方包的情况下,如何在基于Laravel框架上,研发社交系统ThinkSNS+时,简历一套优雅而不失性价比的用户权限管理体系功能,【内含ThinkSNS真实代码】。

需求场景

就是用户组+权限节点,这个需求 laravel 有很多很好的第三方包实现。下面描述代码不参与缓存机制纯数据库查询,给大家提供一个思路。

下面的代码都是来自于ThinkSNS+,是基于 Laravel 全新开发的 ThinkSNS 社交开源项目,遵循 Apache-2.0 开源协议。欢迎 Star 哦。

数据表设计

其实这一块我个人是参考的 Zizaco/entrust 因为我觉得,大多数情况下,我们要用的角色和权限节点都是真多用户的。数据表设计如下:

h7SGVm84q9

可以看到关系如下 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 ZhiyiPlusModelsConcerns;

use ZhiyiPlusModelsRole;
use ZhiyiPlusServicesUserAbility;

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 ZhiyiPlusServices;
use IlluminateSupportCollection;
use ZhiyiPlusModelsUser as UserModel;
use ZhiyiPlusContractsModelUserAbility 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 ZhiyiPlusModels;
use IlluminateDatabaseEloquentModel;

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产品免费体验:http://www.thinksns.com/experience.html

目录
相关文章
|
前端开发 搜索推荐 JavaScript
使用uniapp实现时钟功能
使用uniapp实现时钟功能
492 1
|
7月前
|
开发者 容器
鸿蒙开发:弹性布局Flex
在实际的开发中,需要掌握主轴与交叉轴的关系、换行规则及子元素属性,同时注意性能与兼容性问题,还有一点,Flex组件在渲染时存在二次布局过程,因此在对性能有严格要求的场景下建议使用Column、Row代替。
184 10
鸿蒙开发:弹性布局Flex
双模态后门攻击框架
本研究提出一种融合数据投毒与模型投毒优势的联邦学习双模态后门攻击框架,通过动态协同攻击机制,在数据层面利用生成对抗网络生成自适应触发器,在模型层面引入梯度伪装机制,实现攻击隐蔽性和持续性突破。实验表明,该方案在CIFAR-10和Fashion-MNIST数据集上攻击成功率提升23.7%,并在20轮模型更新中保持后门功能存活。
|
10月前
|
编解码 IDE KVM
Happy coding,明基RD280U使用分享
最近尝试了明基的专业编程显示器 `RD280U`,28寸4K分辨率,3:2屏幕比例,适合编程。支持硬件级防蓝光、抗反射面板,接口丰富,支持KVM。自动亮度调节、编码模式和软件辅助功能,使其在编程体验上表现出色。如果你对专业编程显示器有需求,这无疑是一个不错的选择。
239 12
|
10月前
|
数据采集 JSON Java
利用Java获取京东SKU接口指南
本文介绍如何使用Java通过京东API获取商品SKU信息。首先,需注册京东开放平台账号并创建应用以获取AppKey和AppSecret。接着,查阅API文档了解调用方法。明确商品ID后,构建请求参数并通过HTTP客户端发送请求。最后,解析返回的JSON数据提取SKU信息。注意遵守API调用频率限制及数据保护法规。此方法适用于电商平台及其他数据获取场景。
|
12月前
|
传感器 编解码 人工智能
为 NVIDIA Jetson 和其他嵌入式系统选择合适的摄像头
本文详细介绍了为NVIDIA Jetson和其他嵌入式系统选择合适摄像头模块的关键因素,包括传感器类型(CCD和CMOS)、电子快门(全局快门和滚动快门)、彩色或单色传感器、动态范围、分辨率、帧率和接口等。文章还提供了光学器件的选择建议,并列出了NVIDIA摄像头模块合作伙伴,帮助用户完成从概念到生产的整个设计过程。
180 0
为 NVIDIA Jetson 和其他嵌入式系统选择合适的摄像头
|
消息中间件 存储
RabbitMQ之交换机
【1月更文挑战第9天】 RabbitMQ 消息传递模型的核心思想是: 生产者生产的消息从不会直接发送到队列。实际上,通常生产者甚至都不知道这些消息传递传递到了哪些队列中。 相反,生产者只能将消息发送到交换机(exchange),交换机工作的内容非常简单,一方面它接收来自生产者的消息,另一方面将它们推入队列。交换机必须确切知道如何处理收到的消息。是应该把这些消息放到特定队列还是说把他们到许多队列中还是说应该丢弃它们。这就的由交换机的类型来决定。
360 96
|
Java Go 开发工具
如何排查Go 程序 CPU 占用过高问题
如何排查Go 程序 CPU 占用过高问题
1997 0
如何排查Go 程序 CPU 占用过高问题
|
机器学习/深度学习 自然语言处理 算法
【ChatGPT】一文教你怎么编写清晰有效的(Prompt)提示词~(一)
【ChatGPT】一文教你怎么编写清晰有效的(Prompt)提示词~(一)
|
存储 运维 供应链
运维成本降低 50%,丽迅物流是如何应对大规模容器镜像管理挑战的
通过本文,丽迅物流运维总负责人阳磊分享了关于基于 ACR EE 加速企业业务云原生化进程的实践经验。
运维成本降低 50%,丽迅物流是如何应对大规模容器镜像管理挑战的