Laravel 5.1框架中的ACL用户授权和权限检查功能的实现

发布时间 - 2018-07-31 00:00:00    点击率:

本篇文章给大家分享的内容是关于laravel 5.1框架中的acl用户授权及权限检查功能的实现,有一定的参考价值,希望可以帮助到有需要的朋友。

1、引言

Laravel提供的开箱即用的认证功能使得用户注册、登录、退出和密码重置变得便捷和简单。

但是如果你需要控制访问站点特定部分,或者让非管理员打开/关闭特定页面,又或者确保某些用户只能编辑自己发布的东西(如文章),那么 你就需要引入类似BeatSwitch Lock这样的工具或者自己手动编写这样的功能。我们将这样的功能称之为ACL:Access Control Lists(访问控制列表),用于定义用户基于其用户记录属性操作或查看特定事物的权限。

幸运的是,从Laravel 5.1.11开始,Laravel提供了开箱即用的授权功能用于实现上述需求,我们不再需要做任何额外工作,用就是了。

注:在开始本节之前,请参考升级指南将Laravel升级到Laravel 5.1.11,否则不能实现相关功能。

2、能做什么?

Laravel提供的开箱即用的ACL被称作Gate(这并不是一个类似Spark的产品名称,而只是一个类和门面的名称)。

使用Gate类(注入或使用Gate门面)允许我们轻松检查某个用户(当前登录用户或指定用户)是否允许操作特定事物。检查代码如下:

if (Gate::denies('update-post', $post)) {
    abort(403);
}

将这段代码放到控制器中,它将会使用定义好的规则update-post来检查当前认证用户是否有权限更新指定文章。

你还可以使用Gate::allows,该方法与denies方法相对,还可以在Blade视图模板中通过@can来使用,还有更多更多,让我们接下来一窥究竟。

3、如何使用?

Laravel ACL建立在“权限”概念之上,权限包括一个键(例如update-post)和一个返回true或false的闭包(可传入参数)。

3.1 定义权限

让我们在AuthServiceProvider中定义用户更新文章权限update-post如下:

define('update-post', function ($user, $post) {
            return $user->id === $post->user_id;
        });
    }
}

正如你所看到的,定义权限闭包的第一个参数是指定用户,如果当前用户没有通过登录认证,Gate将会自定返回false。

当然,除了闭包之外,还可以通过类方法作为第二个参数来替代闭包,该类会在容器中解析:

$gate->define('update-post', 'PostPolicy@update');

3.2 通过Gate门面检查权限

Gate提供如下方法进行权限检查:check、allows和denies,check和allows功能用法完全一样,而denies和allows功能相反。

如果你使用门面检查权限,则不需要传递用户实例,Gate门面会自动将当前用户传递进来:

if (Gate::denies('update-post', $post)) {       
    abort(403);
}

如果你在权限中定义了多个参数:

Gate::define('delete-comment', function ($user, $post, $comment) {
    //
});

则检查方法如下:

if (Gate::allows('delete-comment', [$post, $comment])) {
    //
}

如果你想检查非当前认证用户是否有权限操作,调用方法如下:

if (Gate::forUser($user)->allows('update-post', $post)) {
    //
}

3.3 使用Gate注入检查权限

和以往一样,可以注入Gate类而不是使用其门面,注入的类和你在AuthServiceProvider中一样——Illuminate\Contracts\Auth\Access\Gate:

public function somethingResolvedFromContainer(Gate $gate)
{
    if ($gate->denies('update-post')) {
        // etc.
    }
}

3.4 使用User模型检查权限

Laravel的App\User模型现在使用了Authorizabletrait,因此可以使用其提供的can和cannot方法,分别对应Gate的allows和denies方法。

所以我们也可以使用User模型来检查权限:

public function update(Request $request, $id)
{
    $post = Post::findOrFail($id);
    if ($request->user()->cannot('update-post', $post)) {
        abort(403);
    }
    // 更新文章...
}

3.5 在Blade中检查权限

你可以在Blade中使用@can指令来检查权限:

id }}">查看文章
@can('update-post', $post)
    id }}/edit">编辑文章
@endcan

与之相对的是@else指令:

@can('update-post', $post)
    
@else
    
@endcan

3.6 中止权限检查

如果是管理员或超级用户拥有所有权限怎么做?或者你想要为用户临时切换ACL逻辑又该当如何?

Gate提供的before方法允许你在一些特定情况下在执行其他检查前就返回,不再往下检查权限:

$gate->before(function ($user, $ability) {
    if ($user->last_name === 'Stauffer') {
        return true;
    }
});

或者使用用户自己的时候:

$gate->before(function ($user, $ability) {
    if ($user->isOwner()) {
        return true;
    }
});

3.7 策略类

随着应用逻辑越来越复杂,要处理的权限越来越多,将所有权限定义在AuthServiceProvider显然不是一个明智的做法,因此Laravel引入了策略类,策略类是一些原生的PHP类,和控制器基于资源对路由进行分组类似,策略类基于资源对权限进行分组管理。

生成策略类

可以使用如下Artisan命令生成PostPolicy策略类:

php artisan make:policy PostPolicy

生成的策略类位于app/Policies目录。

然后我们可以在AuthServiceProvider的policies属性中注册策略类:

protected $policies = [
    Post::class => PostPolicy::class,
];

下面我们编辑PostPolicy如下:

id === $post->user_id;
    }
}

注:所有策略类都通过服务容器进行解析,这意味着你可以在策略类的构造函数中类型提示任何依赖,它们将会自动被注入。

检查策略

如果为某个资源类型定义了策略类,Gate将会使用第一个参数来判断检查策略类上的哪个方法。

因此,要检查是否有权限更新某篇文章,只需要传入文章实例和update权限:

当然也可以使用User模型和Blade指令检查权限。

此外,Laravel还提供了一个全局帮助函数policy来检查权限:

if (policy($post)->update($user, $post)) {
    //
}

3.8 控制器授权

由于大多数授权都会在检查权限失败的情况下退出控制器方法,因此在控制器中检查权限有一条捷径(AuthorizesRequeststrait提供,该trait在基类控制器Controller中被使用):

authorize('update', $post);
        // 更新文章...
    }
}

和我们上面的例子一样,如果授权失败会抛出403错误。

最后,如果你的控制器方法名和策略类中的方法名相同,例如都是update,则可以省略authorize的第一个参数:

public function update($id){
    $post = Post::findOrFail($id);
    $this->authorize($post);
    // 更新文章...
}

此外,AuthorizesRequests也提供了对非当前认证用户权限检查的支持:

$this->authorizeForUser($user, 'update', $post);

相关文章推荐:

Laravel 5.1框架中如何创建自定义Artisan控制台命令

相关课程推荐:

2017年最新的五个Laravel视频教程推荐


# php  # laravel  # define  # 构造函数  # 闭包  # spark  # Access  # 可以使用  # 第一个  # 将会  # 你在  # 的是  # 如果你  # 即用  # 还可以  # 你可以  # 让我们 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: JavaScript如何实现类型判断_typeof和instanceof有什么区别  如何自定义建站之星模板颜色并下载新样式?  如何在 Python 中将列表项按字母顺序编号(a.、b.、c. …)  网站制作价目表怎么做,珍爱网婚介费用多少?  PythonWeb开发入门教程_Flask快速构建Web应用  邀请函制作网站有哪些,有没有做年会邀请函的网站啊?在线制作,模板很多的那种?  PHP怎么接收前端传的文件路径_处理文件路径参数接收方法【汇总】  如何快速搭建个人网站并优化SEO?  北京网页设计制作网站有哪些,继续教育自动播放怎么设置?  利用vue写todolist单页应用  车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?  Thinkphp 中 distinct 的用法解析  Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验  Laravel的路由模型绑定怎么用_Laravel Route Model Binding简化控制器逻辑  长沙企业网站制作哪家好,长沙水业集团官方网站?  公司门户网站制作流程,华为官网怎么做?  Python制作简易注册登录系统  ChatGPT常用指令模板大全 新手快速上手的万能Prompt合集  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  如何生成腾讯云建站专用兑换码?  Swift中swift中的switch 语句  浅述节点的创建及常见功能的实现  如何在云虚拟主机上快速搭建个人网站?  Win11怎样安装网易有道词典_Win11安装词典教程【步骤】  香港服务器租用每月最低只需15元?  如何在建站宝盒中设置产品搜索功能?  宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程  怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?  html5怎么画眼睛_HT5用Canvas或SVG画眼球瞳孔加JS控制动态【绘制】  如何快速生成专业多端适配建站电话?  Laravel怎么导出Excel文件_Laravel Excel插件使用教程  详解Android中Activity的四大启动模式实验简述  Python面向对象测试方法_mock解析【教程】  昵图网官方站入口 昵图网素材图库官网入口  Laravel数据库迁移怎么用_Laravel Migration管理数据库结构的正确姿势  如何快速启动建站代理加盟业务?  Laravel如何与Vue.js集成_Laravel + Vue前后端分离项目搭建指南  Laravel如何使用Blade模板引擎?(完整语法和示例)  如何利用DOS批处理实现定时关机操作详解  三星、SK海力士获美批准:可向中国出口芯片制造设备  JavaScript常见的五种数组去重的方式  高端建站如何打造兼具美学与转化的品牌官网?  EditPlus中的正则表达式 实战(2)  如何在云主机上快速搭建网站?  Laravel Fortify是什么,和Jetstream有什么关系  潮流网站制作头像软件下载,适合母子的网名有哪些?  如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环  php读取心率传感器数据怎么弄_php获取max30100的心率值【指南】  如何在HTML表单中获取用户输入并用JavaScript动态控制复利计算循环  laravel怎么通过契约(Contracts)编程_laravel契约(Contracts)编程方法