laravel5.5授权系统
背景:
帖子属于某个人(拥有属性user_id),如果这是个私密帖子,只有自己才可以看到,传统的做法是
class PostsController extends Controller
{
public function show($id)
{
$post = Post::findOrFail($id);
//只有登录的用户id和帖子的所属user_id相同才可以通过
if (auth()->id() != $post->user_id) {
// 403 权限错误
abort(403, 'Sorry, not sorrry.');
}
return $post->title;
}
}
以上做法问题不大,但是有没有更优雅的做法呢,今天要讲的就是laravel的用户授权,Laravel 有 2 种主要方式来实现用户授权:gates 和策略。
1. Gates
1.1 一个简单的使用Gates的例子
- 准备工作:
创建迁移文件
php artisan make:migration create_post_table --create=posts
文件内容
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned()->index();
$table->string('title');
$table->text('body');
$table->timestamps();
});
\DB::table('posts')->insert(
array(
'user_id' => 1,
'title' => '学习用户授权',
'body' => '两种方式,Gates、策略',
)
);
开始迁移
php artisan migration
我们主要使用user表(laravel自带迁移文件)和posts表,其它创建Model等工作自行完成
- 注册Gates,在服务提供器中注册
服务提供器 App\Providers\AuthServiceProvider.php
/**
* 注册任意用户认证、用户授权服务。
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', function ($user, $post) {
return $user->id == $post->user_id;
});
}
- 授权判定,可以在控制器中进行权限的判定
控制器 app/Http/Controllers/PostManager.php
public function show($id)
{
$post = Post::findOrFail($id);
if (Gate::allows('update-post', $post)) {
// 指定用户可以更新博客...
}
abort(403, 'Sorry, Permission denied');
}
以上就是一个简单的用户授权,是不是很简单,下面我们理解下更多用法
1.2 编写Gates
典型的做法是在 App\Providers\AuthServiceProvider 类中使用 Gate facade 定义。Gates 接受一个用户实例作为第一个参数,并且可以接受可选参数。
- 匿名函数
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', function ($user, $post) {
return $user->id == $post->user_id;
});
}
- 还可以使用Class@method风格字符串,比如控制器
Gate::define('update-post', 'PostPolicy@update');
- 使用资源Gates
一次性定义多个Gates
Gate::resource('posts', 'PostPolicy');
等同于定义了下面4个功能
Gate::define('posts.view', 'PostPolicy@view');
Gate::define('posts.create', 'PostPolicy@create');
Gate::define('posts.update', 'PostPolicy@update');
Gate::define('posts.delete', 'PostPolicy@delete');
还可以传递第三个参数给resource方法,以增加功能
Gate::resource('posts', 'PostPolicy', [
'image' => 'updateImage',
'photo' => 'updatePhoto',
]);
1.3 授权动作
注意: 上面我们定义Gate的时候,闭包函数第一个参数为$user, 但是你并不需要传递当前认证通过的用户给这些方法。Laravel 会自动处理好传入的用户,然后传递给 gate 闭包函数
- 基本用法,使用Gate Facades
//允许授权
if (Gate::allows('update-post', $post)) {
// 指定用户可以更新博客...
}
//否定授权
if (Gate::denies('update-post', $post)) {
// 指定用户不能更新博客...
}
- 不需自动处理用户,自己指定一个用户,可以使用Gate Facade的forUser()方法
if (Gate::forUser($user)->allows('update-post', $post)) {
// 指定用户可以更新博客...
}
if (Gate::forUser($user)->denies('update-post', $post)) {
// 指定用户不能更新博客...
}
2. policy策略
显然Gates简单易用,但是当我们需要授权的动作过多的时候,就显得比较臃肿了,管理起来麻烦,laravel提供了我们另一种方式,来实现同样的功能,就是policy
2.1 还是先看个例子
- 创建策略文件
php artisan make:policy PostPolicy --model=Post
- 编写文件
以上命令会在app\Policies\PostPolicy.php文件,该文件已经包含了4个基本的「CRUD」策略方法,我们可以增删各种方法,这里只补充view方法
public function view(User $user, Post $post)
{
//
return $user->id == $post->user_id;
}
public function create(User $user)
{
//
}
public function update(User $user, Post $post)
{
//
}
public function delete(User $user, Post $post)
{
//
}
- 注册策略
服务提供器 App\Providers\AuthServiceProvider.php, 更改$policies属性
protected $policies = [
'App\Post' => 'App\Policies\PostPolicy',
];
- 授权判定
控制器 app/Http/Controllers/PostManager.php
public function show($id)
{
$post = Post::findOrFail($id);
if ($user->can('views', $post)) {
// 指定用户可以 ......
}
abort(403, 'Sorry, Permission denied');
}
以上就是使用policy的一个简单实例,下面还是进行更细致的梳理
2.2 编写策略
生成策略文件后,我们可以自己创建删除方法,以满足我们的需求,可以为自定义策略方法使用自己喜欢的名字
public function view(User $user, Post $post)
{
//
return $user->id == $post->user_id;
}
public function create(User $user)
{
//
}
// 其它更多需要的方法
我们还可以使用策略过滤器
比如我们想要超级管理员有所有权限,可以在策略中定义一个 before 方法
public function before($user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
如果你想拒绝用户所有的授权,你应该在 before 方法中返回 false。如果返回的是 null,则通过其它的策略方法来决定授权与否。
2.3 授权策略
2.3.1 通过用户模型
- 指定模型的动作
Laravel 应用内置的 User 模型包含 2 个有用的方法来授权动作:can 和 cant
if ($user->can('update', $post)) {
//
}
if ($user->cant('update', $post)) {
//
}
注意: 如果指定模型的 策略已被注册,can 方法会自动调用核实的策略方法并且返回 boolean 值。如果没有策略注册到这个模型,can 方法会尝试调用和动作名相匹配的基于闭包的 Gate。
- 不指定模型的动作
比较下面的两个方法
public function view(User $user, Post $post)
{
//
return $user->id == $post->user_id;
}
public function create(User $user)
{
//
}
试想,如果我们有另个一个VideoPolice, 同样有view和create方法。
public function view(User $user, Video $video)
{
//
return $user->id == $video->user_id;
}
public function create(User $user)
{
//
}
不难想象,尽管第一参数都是view, 第二个传入了模型实例,我们在注册策略的时候做了模型和策略的映射,这样就可以区分使用的是PostPolicy还是VideoPolicy
$user->can('view', $post);
$user->can('view', $video);
那么create方法呢, 我们可以传递一个类名给 can 方法。当授权动作时,这个类名将被用来判断使用哪个策略
$user->can('create', Post::class);
$user->can('view', Video::class);
2.3.2 通过中间件
- 通过隐式模型绑定,指定模型动作
use App\Post;
Route::put('/post/{post}', function (Post $post) {
// 当前用户可以更新博客...
})->middleware('can:update,post');
关于隐式模型绑定,这里顺便提一下,更详细的请自己查询。
首先可以定义这样一条路由
Route::get('/test/{post}','TestController@test');
控制器引入模型文件
use App\Http\Model\Post;
test方法传入实例,并类型提示
public function test(Post $post)
{
http_response_code(500);
dd($post);
}
我们访问这样的一条路由 http://xxxx.com/test/1 ,将dd()出id=1 的post实例,我们并没有专门的实例化post这个model,但是我们自动返回了id=参数的post实例
- 不需要指定模型的动作
Route::post('/post', function () {
// 当前用户可以创建博客...
})->middleware('can:create,App\Post');
2.3.3 通过控制器辅助函数autorize()
如果动作不被授权,authorize 方法会抛出 Illuminate\Auth\Access\AuthorizationException 异常,然后被 Laravel 默认的异常处理器转化为带有 403 状态码的 HTTP 响应:
- 指定模型动作
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// 当前用户可以更新博客...
}
- 不指定模型动作
public function create(Request $request)
{
$this->authorize('create', Post::class);
// 当前用户可以新建博客...
}
2.3.4 通过blade模板
可以使用@can 和 @cannot
- 指定模型动作
@can('update', $post)
<!-- 当前用户可以更新博客 -->
@elsecan('create', $post)
<!-- 当前用户可以新建博客 -->
@endcan
@cannot('update', $post)
<!-- 当前用户不可以更新博客 -->
@elsecannot('create', $post)
<!-- 当前用户不可以新建博客 -->
@endcannot
- 不指定模型动作
@can('create', App\Post::class)
<!-- 当前用户可以新建博客 -->
@endcan
@cannot('create', App\Post::class)
<!-- 当前用户不可以新建博客 -->
@endcannot
实际上@can 和@cannot 提供了方便的缩写, 分别等同于下面写法
@if (Auth::user()->can('update', $post))
<!-- 当前用户可以更新博客 -->
@endif
@unless (Auth::user()->can('update', $post))
<!-- 当前用户不可以更新博客 -->
@endunless
laravel5.5授权系统的更多相关文章
- Python+Django+SAE系列教程17-----authauth (认证与授权)系统1
通过session,我们能够在多次浏览器请求中保持数据,接下来的部分就是用session来处理用户登录了. 当然,不能仅凭用户的一面之词,我们就相信,所以我们须要认证. 当然了,Django 也提供了 ...
- 02 【PMP】项目管理系统、PMIS、工作授权系统、配置管理系统、变更管理
PMBOK融会贯通:盘点八大系统<项目管理系统.PMIS.工作授权系统.配置管理系统.变更管理> 一. PMBOK相关系统: 工作系统作为事业环境因素,提高或限制项目管理的灵活性,并 ...
- 分享一个单点登录、OAuth2.0授权系统源码(SimpleSSO)
SimpleSSO 关于OAuth 2.0介绍: http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 系统效果: 登录界面: 首页: 应用界面: ...
- .Net Core 授权系统组件解析
前面关于.Net Core如何进行用户认证的核心流程介绍完毕之后,.Net Core 认证系统之Cookie认证源码解析远程认证暂时不介绍,后期有时间,我会加上.接下去介绍认证组件是如何和认证组件一起 ...
- laravel5.5 调用系统自带登陆认证auth
1执行命令 php artisan make:auth 2 编辑文件 config/auth guardes 'admin' => [ 'driver' => 'session', 'pr ...
- laravel5.5缓存系统
目录 1 Redis的配置 1.1 安装PRedis 1.2 配置 1.2.1 配置redis数据库 1.2.2 更改session的配置 1.2.3 更改cache配置 1.3 使用redis 2 ...
- ABP框架 - 授权
文档目录 本节内容: 简介 关于 IPermissionChecker 定义许可 检查许可 使用 AbpAuthorize特性 AbpAuthorize特性注意事项 废止授权 使用 IPermissi ...
- ABP理论学习之授权(Authorization)
返回总目录 本篇目录 介绍 定义权限 检查权限 使用AbpAuthorize特性 使用IPermissionChecker Razor视图 客户端(Javascript) 权限管理者 介绍 几乎所有的 ...
- mysql系统数据库
mysql系统数据库主要存储了一些存储MySQL服务的系统信息表.一般情况下mysql库的表都是MYASIM引擎,除非个别情况.mysql库的表的作用大致可以分为以下几类: (1)授权系统表 (2)系 ...
随机推荐
- php中的curl_multi的应用(php多进程)
相信许多人对PHP手册中语焉不详的curl_multi一族的函数头疼不已,它们文档少,给的例子 更是简单的让你无从借鉴,我也曾经找了许多网页,都没见一个完整的应用例子. curl_multi_add_ ...
- centos 7中磁盘挂载重启后挂载失效
在centos 7磁盘挂载成功后,关机重启,挂载磁盘失效,需要重新挂载,不用重新挂载的开机挂载方法如下: 1.先检验要挂载的磁盘是否已被挂载,有的话先卸除 2.修改 /etc/fstab 文件 ,最 ...
- react+webpack 引入字体图标
在使用react+webpack 构建项目过程中免不了要用到字体图标,在引入过程中报错,不能识别字体图标文件中的@符,报错 Uncaught Error: Module parse failed: U ...
- CVE-2017-8464 LNK文件(快捷方式)远程代码执行漏洞复现
北京时间2017年6月13日凌晨,微软官方发布6月安全补丁程序,“震网三代” LNK文件远程代码执行漏洞(CVE-2017-8464)和Windows搜索远程命令执行漏洞(CVE-2017-8543) ...
- 【转】Android UI开发第三十一篇——Android的Holo Theme
好长时间没写Android UI方面的文章了,今天就闲扯一下Android的Holo主题.一直做android开发的可能都知道,Android 系统的UI有过两次大的变化,一次是android 3.0 ...
- 线程 task训练
1. task类表示一个线程,最简单的task的构造方法是 ,参数是Action<t>,是一个无返回值的泛型委托. 指向要执行的函数.当调用·start()方法时,就执行子线程.执行指向的 ...
- Linux---who命令学习
who命令 获取正在登录系统的用户 使用Linux的who命令 第一个参数book代表用户名,第二个参数tty7代表终端名,第三个参数代表时间,第四个参数代表用户的登录地址. 阅读手册 使用命令读手册 ...
- 基于java开发的开源代码GPS北斗位置服务监控平台
最近在研究位置服务平台,基于全球卫星定位技术(GNSS).互联网技术.空间地理信息技术(GIS).3G/4G无线通信技术,面向全国公众用户建立大容量.实时.稳定的位置信息服务运营平台.实现管理目标的实 ...
- Vue源码学习三 ———— Vue构造函数包装
Vue源码学习二 是对Vue的原型对象的包装,最后从Vue的出生文件导出了 Vue这个构造函数 来到 src/core/index.js 代码是: import Vue from './instanc ...
- Github学生包的申请
Github Education为了大学生们更好的进行开发,进行边做边学,与一些合作伙伴和朋友一起创建GitHub学生开发者包. 里面内容非常丰富,应有尽有: AWS 亚马逊云服务 $75-$150 ...