Laravel 用户授权:判断是否授权
我们可以通过下面的几个方法来判断是否授权
使用策略授权动作
通过用户模型
Laravel 内置的 User
模型包含两个有用的方法来授权动作: can
和 cant
。这个 can
方法需要指定授权的动作以及相关的模型。例如,判断是否授权一个用户更新指定的 Post
模型:
if ($user->can('update', $post)) {
//
}
如果指定模型的 「策略已被注册」, can
方法会自动调用合适的策略并返回一个 boolean 值。如果没有策略注册到这个模型,can
方法会尝试调用和指定动作名称相匹配的基于闭包的 Gate。
不需要指定模型的动作
记住,一些动作,比如 create
并不需要指定模型实例。在这种情况下,可传递一个类名给 can
方法。这个类名将被用于判定使用哪种策略授权动作:
use App\Post;
if ($user->can('create', Post::class)) {
// 执行相关策略中的 "create" 方法...
}
通过中间件
Laravel 包含一个可以在请求到达路由或者控制器之前就进行动作授权的中间件。默认情况下, Illuminate\Auth\Middleware\Authorize
中间件被指定到你的 App\Http\Kernel
类中的 can
键上。让我们用一个授权用户更新博客的例子来讲解一下 can
这个中间件的使用:
use App\Post;
Route::put('/post/{post}', function (Post $post) {
// 当前用户可以进行更新操作...
})->middleware('can:update,post');
在这个例子中,我们传给了 can
中间件两个参数。第一个参数是需要授权的动作名称,第二个参数是我们希望传递给策略方法的路由参数。在这种情况下,我们使用了「 隐式路由绑定」,一个 Post
模型会被传递给策略方法。如果用户不被授权访问指定的动作,这个中间件将会生成带有 403
状态码的 HTTP 响应。
通过控制器辅助函数
除了在 User
模型中提供辅助方法以外,Laravel 也为继承 App\Http\Controllers\Controller
这个基类的控制器提供了一个有用的 authorize
方法。就像 can
方法一样,这个方法需要接收你想授权的动作和相关的模型作为参数。如果这个动作没有被授权, authorize
方法会抛出一个 Illuminate\Auth\Access\AuthorizationException
的异常,然后 Laravel 默认的异常处理器会将这个异常转化成带有 403
状态码的 HTTP 响应。
<?php
namespace App\Http\Controllers;
use App\Post;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
/**
* 更新指定博客帖子。
*
* @param Request $request
* @param Post $post
* @return Response
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// 当前用户可以更新博客...
}
}
不需要指定模型的动作
和之前讨论的一样,一些动作,比如 create
并不需要指定模型实例的动作。在这种情况下,你可以传递一个类名给 authorize
方法。当授权这个动作时,这个类名将被用来判断使用哪个策略:
/**
* 创建一个新的博客
*
* @param Request $request
* @return Response
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create(Request $request)
{
$this->authorize('create', Post::class);
// 当前用户可以新建博客...
}
授权资源控制器
如果你使用的是 资源控制器,那么你就可以在控制器构造方法里使用 authorizeResource
方法。该方法会把合适 can
中间件附加到资源控制器相应的方法中。
authorizeResource
方法接收模板类名作为第一个参数,包含模型 ID 的路由 / 请求参数的名称作为其第二个参数:
<?php
namespace App\Http\Controllers;
use App\Post;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class PostController extends Controller
{
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
}
通过 Blade 模板
当编写 Blade 模板时,你可能希望页面的指定部分只展示给授权访问指定动作的用户。比如,你可能希望只展示更新的表单给有权更新博客的用户。在这样情况下,你可以使用 @can
和 @cannot
等一系列指令:
@can('update', $post)
<!-- The Current User Can Update The Post -->
@elsecan('create', App\Post::class)
<!-- The Current User Can Create New Post -->
@endcan
@cannot('update', $post)
<!-- The Current User Can't Update The Post -->
@elsecannot('create', App\Post::class)
<!-- The Current User Can't Create New Post -->
@endcannot
这些指令是编写 @if
和 @unless
语句的捷径。 @can
和 @cannot
语句分别转化为以下语句:
@if (Auth::user()->can('update', $post))
<!-- The Current User Can Update The Post -->
@endif
@unless (Auth::user()->can('update', $post))
<!-- The Current User Can't Update The Post -->
@endunless
不依赖模型的动作
与大多数其他授权方法一样,如果动作不需要模型实例,则可以将类名传递给 @ can
和 @ cannot
指令:
@can('create', App\Post::class)
<!-- The Current User Can Create Posts -->
@endcan
@cannot('create', App\Post::class)
<!-- The Current User Can't Create Posts -->
@endcannot