Laravel授权策略之用户只能编辑自己的资料

在完成对未登录用户的限制之后,接下来我们要限制的是已登录用户的操作,当 id 为 1 的用户去尝试更新 id 为 2 的用户信息时,我们应该返回一个 403 禁止访问的异常。在 Laravel 中可以使用 授权策略 (Policy) 来对用户的操作权限进行验证,在用户未经授权进行操作时将返回 403 禁止访问的异常。

我们可以使用以下命令来生成一个名为 UserPolicy 的授权策略类文件,用于管理用户模型的授权。

1
$ php artisan make:policy UserPolicy

所有生成的授权策略文件都会被放置在 app/Policies 文件夹下。

让我们为默认生成的用户授权策略添加 edit方法,用于用户更新时的权限验证。

app/Policies/UserPolicy.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

namespace App\Policies;

use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class UserPolicy
{
use HandlesAuthorization;

/**
* Create a new policy instance.
*
* @return void
*/
public function __construct()
{
//
}

//禁止已登录用户修改其他用户资料
public function edit(User $current, User $user){
return $current->id === $user->id;
}
}

edit方法接收两个参数,第一个参数默认为当前登录用户实例,第二个参数则为要进行授权的用户实例。当两个 id 相同时,则代表两个用户是相同用户,用户通过授权,可以接着进行下一个操作。如果 id 不相同的话,将抛出 403 异常信息来拒绝访问。

使用授权策略需要注意以下两点:

  1. 我们并不需要检查 $current 是不是 NULL。未登录用户,框架会自动为其 所有权限 返回 false
  2. 调用时,默认情况下,我们 不需要 传递当前登录用户至该方法内,因为框架会自动加载当前登录用户(接着看下去,后面有例子);

接下来我们还需要在 AuthServiceProvider 类中对授权策略进行设置。AuthServiceProvider 包含了一个 policies 属性,该属性用于将各种模型对应到管理它们的授权策略上。我们需要为用户模型 User 指定授权策略 UserPolicy

app/Providers/AuthServiceProvider.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php

namespace App\Providers;

use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
'App\User' => 'App\Policies\UserPolicy'
];

/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();

//
}
}

授权策略定义完成之后,我们便可以通过在用户控制器中使用 authorize 方法来验证用户授权策略。默认的 App\Http\Controllers\Controller 类包含了 LaravelAuthorizesRequests trait。此 trait 提供了 authorize方法,它可以被用于快速授权一个指定的行为,当无权限运行该行为时会抛出 HttpExceptionauthorize 方法接收两个参数,第一个为授权策略的名称,第二个为进行授权验证的数据。

我们需要为 editupdate 方法加上这行:

1
$this->authorize('edit', $user);

这里 edit 是指授权类里的 edit 授权方法,$user 对应传参 edit 授权方法的第二个参数。正如上面定义 edit 授权方法时候提起的,调用时,默认情况下,我们 不需要 传递第一个参数,也就是当前登录用户至该方法内,因为框架会自动加载当前登录用户。

书写的位置如下:

app/Http/Controllers/UsersController.php

1
2
3
4
5
public function edit(User $user)
{
$this->authorize('edit', $user);
return view('admin.user.edit', ['user'=>$user]);
}

现在,使用 id 为 1 的用户登录,当访问 id 为 2 的用户编辑页面系统将会拒绝访问。

为了更友好的显示,建议大家都在view/errors里创建一个403.blade.php文件

再次刷新该页面则显示