Laravel学习记录--Laravel用户授权系统

简介

在Laravel中为我们提供了一种简单的方式来处理用户授权动作,主要有两种方式GatesPolicy(策略),可以将其类比路由器(Gates)和控制器(PolicyGates提供了一个简单的,基于闭包的方式来进行授权认证,而Policy在特定的模型或资源中通过分组来实现授权认证的逻辑
这两种方式都能进行用户权限认证,但Gates一般用于与模型和资源无关的地方,如查看管理员后台,而Policy则用于特定的模型或者资源中

Gates

Gates是用来决定用户是否被授权执行给定的动作的闭包函数,并且典型的做法是在App\Providers\AuthServiceProvider类中使用Gate门面定义。

define('授权动作名''动作逻辑')

Gates闭包函数接受两个参数
第一个参数:用户实例
第二个参数:(可选)如相关的Eloquent模型
如下例
boot方法中 判断用户是否有权限更新当前文章,返回true/false

 public function boot()
    {
        $this->registerPolicies();
       Gate::define('update-post',function($user,$post){
            return $user->id == $post->user_id
        })
    }

同样Gates也是使用class@method的风格回调字符串来定义如

 Gate::define('update-post','PostPolicy@update')

资源Gates
我们还可以使用 resource方法一次性定义多个Gate功能;像资源控制器那样

Gate::resource('post','PostPolicy')
//创建一个资源Gate

资源Gate会定义以下Gates

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']);

生成如下Gates

Gate::define('posts.view','PostPolicy@view');
Gate::define('posts.create','PostPolicy@create');
Gate::define('posts.update','PostPolicy@update');
Gate::define('posts.delete','PostPolicy`在这里插入代码片`@delete');
Gate::define('posts.image','PostPolicy@updateImage');
Gate::define('posts.photo','PostPolicy@updatePhoto');

授权动作
使用Gates来授权动作时,应该使用allowsdeies方法,这里你并不需要传递当前认证通过的用户给这些方法,,Laravel会自动处理好传入的用户,然后传递给Gate闭包函数

 public function root(){
    	$post = Post::find(1);//获取文章实例
    	if(Gate::allows('update-post',$post)){
    	    //如果有更新权限
    		dump('当前用户可以更新此博客');
    	}
    	if(Gate::denies('update-post',$post)){
    	    //如果没有更新权限
    		dump('当前用户不能更新此博客');
    	}
    }

这里是判断当前登录用户的权限,如果你想指定一个特定用户的权限,可以通过Gate门面的forUser方法,传入用户实例

  public function root(){
    	$user = User::find(3);
    	$post = Post::find(1);
    	if(Gate::forUser($user)->allows('update-post',$post)){
    		//指定的用户可以更新的博客
    		dump('主编更新所有博客');
    	}

创建策略(Policy)
策略是在特定模型或者资源中组织授权逻辑的类,如我们做一个博客系统,会有一个Post模型和与之对应的PostPolicy类来授权用户的动作。
可以使用artisan命令make:policy创建策略,生成的策略存放在app\Policies目录下
php artisan make:policy PostPolicy 该命令会生成一个空的策略类
如果你想生成的策略类包含[CRUD·](view,create,update,delete)可使用以下命令
php artisan make:policy PostPolicy --model=Post
注册策略
创建好策略后我们需将他注册,在AuthServiceProviderplicies属性,建立模型与对应策略的映射

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

编写策略
注册了策略后我们可以为每个授权的动作添加方法,如
PostPolicy中定义一个update方法,在这个方法中判断用户是否可以更新某篇文章
update方法接受两个参数,UserPost实例,并且返回值为truefalse以此来判断用户是否可以更新谋篇文章

   //判断用户是否可以更新某篇文章
     public function update(User $user, $post)
    {
        dump('用户id:'.$user->id);
        dump('文章用户id:'.$post->user_id);
        return $user->id == $post->user_id;

    }

不包含模型方法
一些策略方法只接受当前认证通过的用户作为参数,而不用传入相关模型实例。如create动作
当创建一篇博客时,我们需要检测用户是否有权限创建博客
定义方法如下

public function create(User $user)
{
    
}

策略过滤器
如果你想通过策略指定一个特定用户的获取所有权限,可以在策略中定义一个before方法,before方法会在策略的其他方法之前执行

 public function before(User $user){
        if($user->id==1){
           //假定id为1的用户拥有所有权限
            return true;
        }
    }

相对的,拒绝用户所有权限,返回false

使用策略授权动作

通过用户模型

Laravel内置额User模型包含2个方法来获取授权动作cancantcan方法需要指定授权的动作和相关的模型,如判断一个用户是否授权更新指定的Post模型

 $user = User::find(Auth::id());
        $post = Post::find(2);	
    	if($user->can('update',$post)){
    		dump('当前用户可以更新文章');
    	}
    	if($user->cant('update',$post)){
    		// dump($post);
    		dump('当前用户不能更新文章');
    	}

注意:can 方法不能静态调用

使用can/cant方法有两种情况
1.指定模型与对应策略建立了映射关系:这种情况can/cant方法会自动调用策略方法并返回布尔值
2.指定模型与对应策略没有建立映射关系:这种情况can/cant方法会尝试调用和动作名相匹配的基于闭包的Gate
不指定模型的授权动作
一些动作,如create并不需要指定模型实例,在这种情况下,可传递一个类名给can方法。当授权动作时,这个类名用于判断使用的是哪个策略

if($user->can('create',Post::class)){

}
通过中间件

Laravel包含一个可以在请求到达路由或控制器之前就进行动作授权的中间件,默认
Illuminate\Auth\Middleware\Authorize中间件被指定到App\Http\Kernel类的can键上。
如:

//路由
Route::get('/test/{post}','TestControler@root')->middleware('can:update,post');
//控制器
public function root(Post $post){
    	dump('用户可以更新文章');
   }
 

上述代码中我们调用中间件can并传递了两个参数,第一个为需要授权的动作名,第二个参数是模型实例,由于这里使用了隐式模型绑定,所以Post会传递到策略方法中,当用户不具备权限时,中间件会生成带有403状态码的HTTP响应
用户具有权限
Laravel学习记录--Laravel用户授权系统_第1张图片
用户不具权限
Laravel学习记录--Laravel用户授权系统_第2张图片

通过控制器辅助函数

除了在User模型中提供辅助方法外,Laravel也为所有继承了App\Http\Controllers\Controller基类的控制器提供了一个有用的authorize方法。和can方法类似,这个方法接收需要授权的动作和相关的模型作为参数,如果动作不被授权,authorize方法会抛出Illuminate\Auth\ Access\AuthorizationException异常,然后被Laravel默认的异常处理转化为带有403状态码的HTTP响应:
正常拥有权限

if( $this->authorize('update', $post)){
    			dump('当前用户可以更新');
}

Laravel学习记录--Laravel用户授权系统_第3张图片
当用户没有权限,抛出异常
Laravel学习记录--Laravel用户授权系统_第4张图片

不指定模型的动作
当你不用指定模型实例,需要传递一个类名给authorize方法

public function create(Request $request)
{
    $this->authorize('create', Post::class);

    // 当前用户可以新建博客...
}
通过Blade模板

当编写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)
@enncannot
<!DOCTYPE html>
<html>
<head>
	<title>测试模板</title>
</head>
<body>
	<h1>用户授权认证</h1>
	{{$post}}
	@can('update',$post)
    <div style='background: skyblue;width:300px;height:150px'>
    	用户更新权限
    @endcan
    @cannot('update',$post)
      <div style='background: #eee;width:300px;height:150px'>
    	普通用户
    </div>
    @endcannot

</body>
</html>

有权限用户
Laravel学习记录--Laravel用户授权系统_第5张图片
没有权限用户
Laravel学习记录--Laravel用户授权系统_第6张图片

你可能感兴趣的:(laravel)