Laravel中的门和策略

今天,我们将讨论 Laravel Web 框架的授权系统。 Laravel 框架以门和策略的形式实现授权。在介绍了门和策略之后,我将通过实现一个自定义示例来演示这些概念。
我假设您已经了解内置的 Laravel 身份验证系统,因为这是理解授权概念所必需的。显然,授权系统与认证系统一起工作来识别合法的用户会话。
如果您不了解 Laravel 身份验证系统,我强烈建议您阅读官方文档,它可以让您深入了解该主题。
Laravel 的授权方法
现在,您应该已经知道 Laravel 授权系统有两种形式:门和策略。虽然这听起来像是一件复杂的事情,但我想说,一旦掌握了它的窍门,它就很容易实现!
Gate 允许您使用简单的基于闭包的方法定义授权规则。换句话说,当您想要授权与任何特定模型无关的操作时,门是实现该逻辑的完美位置。
让我们快速了解一下基于门的授权是什么样的:
...
...
Gate::define('update-post', function ($user, $post) {
return $user->id == $post->user_id;
});
...
...
上面的代码片段定义了授权规则 update-post 您可以从应用程序中的任何位置调用它。
另一方面,当您想要对任何模型的授权逻辑进行分组时,您应该使用策略。例如,假设您的应用程序中有一个 Post 模型,并且您想要授权该模型的 CRUD 操作。在这种情况下,这就是您需要实施的策略。
class PostPolicy
{
public function view(User $user, Post $post) {}
public function create(User $user) {}
public function update(User $user, Post $post) {}
public function delete(User $user, Post $post) {}
}
如您所见,这是一个非常简单的策略类,定义了 Post 模型的 CRUD 操作的授权。
这就是 Laravel 中的门和策略的介绍。从下一节开始,我们将对每个元素进行实际演示。
大门
在本节中,我们将通过一个现实示例来理解门的概念。
如何创建自定义门
当您需要注册组件或服务时,您通常会寻找 Laravel 服务提供者。遵循该约定,让我们继续在 app/Providers/AuthServiceProvider.php 中定义自定义门,如以下代码片段所示。
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('update-post', function ($user, $post) {
return $user->id == $post->user_id;
});
}
}
在 boot 方法中,我们定义了自定义门:
Gate::define('update-post', function ($user, $post) {
return $user->id == $post->user_id;
});
定义门时,它需要一个闭包,根据门定义中定义的授权逻辑,返回 TRUE 或 FALSE 。除了闭包函数之外,还有其他方法可以定义门。
例如,以下门定义调用控制器操作而不是闭包函数。
Gate::define('update-post', 'ControllerName@MethodName');
如何使用我们的自定义大门
现在,让我们继续添加自定义路由,以便我们可以演示基于门的授权如何工作。在路由文件 routes/web.php 中,添加以下路由。
Route::get('service/post/gate', 'PostController@gate');
让我们也创建一个关联的控制器文件app/Http/Controllers/PostController.php。
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Post;
use Illuminate\Support\Facades\Gate;
class PostController extends Controller
{
/* Make sure you don't use Gate and Policy altogether for the same Model/Resource */
public function gate()
{
$post = Post::find(1);
if (Gate::allows('update-post', $post)) {
echo 'Allowed';
} else {
echo 'Not Allowed';
}
exit;
}
}
在大多数情况下,您最终会使用 allows 或 denies 方法(Gate 外观)来授权特定操作。在上面的示例中,我们使用 allows 方法来检查当前用户是否能够执行 update-post 操作。
眼尖的用户会注意到我们只将第二个参数 $post 传递给了闭包。第一个参数是当前登录的用户,由 Gate 门面自动注入。
这就是您应该如何使用门来授权 Laravel 应用程序中的操作。如果您希望为模型实现授权,下一节将介绍如何使用策略。
政策
正如我们之前讨论的,当您想要对任何特定模型或资源的授权操作进行逻辑分组时,您需要的就是策略。
如何创建自定义策略
在本节中,我们将为 Post 模型创建一个策略,用于授权所有 CRUD 操作。我假设您已经在应用程序中实现了 Post 模型;否则,类似的事情也会做。
Laravel artisan 命令是创建存根代码时最好的朋友。您可以使用以下 artisan 命令为 Post 模型创建策略。
$php artisan make:policy PostPolicy --model=Post
如您所见,我们提供了 --model=Post 参数,以便它创建所有 CRUD 方法。如果没有,它将创建一个空白策略类。您可以在 app/Policies/PostPolicy.php 中找到新创建的策略类。
<?php
namespace App\Policies;
use App\Post;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class PostPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* @param \App\User $user
* @return mixed
*/
public function viewAny(User $user)
{
//
}
/**
* Determine whether the user can view the model.
*
* @param \App\User $user
* @param \App\Post $post
* @return mixed
*/
public function view(User $user, Post $post)
{
//
}
/**
* Determine whether the user can create models.
*
* @param \App\User $user
* @return mixed
*/
public function create(User $user)
{
//
}
/**
* Determine whether the user can update the model.
*
* @param \App\User $user
* @param \App\Post $post
* @return mixed
*/
public function update(User $user, Post $post)
{
//
}
/**
* Determine whether the user can delete the model.
*
* @param \App\User $user
* @param \App\Post $post
* @return mixed
*/
public function delete(User $user, Post $post)
{
//
}
/**
* Determine whether the user can restore the model.
*
* @param \App\User $user
* @param \App\Post $post
* @return mixed
*/
public function restore(User $user, Post $post)
{
//
}
/**
* Determine whether the user can permanently delete the model.
*
* @param \App\User $user
* @param \App\Post $post
* @return mixed
*/
public function forceDelete(User $user, Post $post)
{
//
}
}
让我们将其替换为以下代码。
<?php
namespace App\Policies;
use App\User;
use App\Post;
use Illuminate\Auth\Access\HandlesAuthorization;
class PostPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view the post.
*
* @param \App\User $user
* @param \App\Post $post
* @return mixed
*/
public function view(User $user, Post $post)
{
return TRUE;
}
/**
* Determine whether the user can create posts.
*
* @param \App\User $user
* @return mixed
*/
public function create(User $user)
{
return $user->id > 0;
}
/**
* Determine whether the user can update the post.
*
* @param \App\User $user
* @param \App\Post $post
* @return mixed
*/
public function update(User $user, Post $post)
{
return $user->id == $post->user_id;
}
/**
* Determine whether the user can delete the post.
*
* @param \App\User $user
* @param \App\Post $post
* @return mixed
*/
public function delete(User $user, Post $post)
{
return $user->id == $post->user_id;
}
}
为了能够使用我们的策略类,我们需要使用 Laravel 服务提供者注册它,如以下代码片段所示。
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use App\Post;
use App\Policies\PostPolicy;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
Post::class => PostPolicy::class
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
}
}
我们已在 $policies 属性中添加了策略映射。它告诉 Laravel 调用相应的策略方法来授权 CRUD 操作。
您还需要使用 registerPolicies 方法注册策略,就像我们在 boot 方法中所做的那样。
没有模型的策略方法
PostPolicy 策略类中的 create 方法仅采用单个参数,这与采用两个参数的其他模型方法不同。一般来说,第二个参数是模型对象,您将在执行授权时使用它。但是,在 create 方法的情况下,您只需要检查是否允许相关用户创建新帖子。
在下一节中,我们将了解如何使用自定义策略类。
如何使用我们的自定义策略类
更进一步,让我们在 routes/web.php 文件中创建几个自定义路由,以便我们可以在那里测试我们的策略方法。
Route::get('service/post/view', 'PostController@view');
Route::get('service/post/create', 'PostController@create');
Route::get('service/post/update', 'PostController@update');
Route::get('service/post/delete', 'PostController@delete');
最后,让我们在 app/Http/Controllers/PostController.php 创建一个关联的控制器。
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Post;
use Illuminate\Support\Facades\Auth;
class PostController extends Controller
{
public function view()
{
// get current logged in user
$user = Auth::user();
// load post
$post = Post::find(1);
if ($user->can('view', $post)) {
echo "Current logged in user is allowed to update the Post: {$post->id}";
} else {
echo 'Not Authorized.';
}
}
public function create()
{
// get current logged in user
$user = Auth::user();
if ($user->can('create', Post::class)) {
echo 'Current logged in user is allowed to create new posts.';
} else {
echo 'Not Authorized';
}
exit;
}
public function update()
{
// get current logged in user
$user = Auth::user();
// load post
$post = Post::find(1);
if ($user->can('update', $post)) {
echo "Current logged in user is allowed to update the Post: {$post->id}";
} else {
echo 'Not Authorized.';
}
}
public function delete()
{
// get current logged in user
$user = Auth::user();
// load post
$post = Post::find(1);
if ($user->can('delete', $post)) {
echo "Current logged in user is allowed to delete the Post: {$post->id}";
} else {
echo 'Not Authorized.';
}
}
}
您可以通过不同的方式使用策略来授权您的操作。在上面的示例中,我们使用 User 模型来授权我们的 Post 模型操作。
User 模型提供了两种有用的授权方法 — can 和 cant。 can 方法用于检查当前用户是否能够执行某个操作。而与 can 方法对应的 cant 方法,用于判断动作是否无法执行。
让我们从控制器中获取 view 方法的片段,看看它到底做了什么。
public function view()
{
// get current logged in user
$user = Auth::user();
// load post
$post = Post::find(1);
if ($user->can('view', $post)) {
echo "Current logged in user is allowed to update the Post: {$post->id}";
} else {
echo 'Not Authorized.';
}
}
首先,我们加载当前登录的用户,这为我们提供了 User 模型的对象。接下来,我们使用 Post 模型加载示例帖子。
接下来,我们使用 User 模型的 can 方法来授权 Post 模型的 view 操作。 can 方法的第一个参数是您要授权的操作名称,第二个参数是您要授权的模型对象。
这是如何使用 User 模型通过策略授权操作的演示。或者,如果您在控制器中授权某个操作,则也可以使用控制器助手。
…
$this->authorize('view', $post);
…
如您所见,如果您使用控制器助手,则无需加载 User 模型。
如何通过中间件使用策略
或者,Laravel 还允许您使用中间件授权操作。让我们快速查看以下代码片段,了解如何使用中间件来授权模型操作。
Route::put('/post/{post}', function (Post $post) {
// Currently logged-in user is allowed to update this post....
})->middleware('can:update,post');
在上面的示例中,它将使用 can 中间件。我们传递两个参数:第一个参数是我们想要授权的操作,第二个参数是路由参数。根据隐式模型绑定的规则,第二个参数会自动转换为 Post 模型对象,并作为第二个参数传递。如果当前登录的用户无权执行 update 操作,Laravel 将返回 403 状态代码错误。
如何将策略与刀片模板结合使用
如果您希望在登录用户被授权执行特定操作时显示代码片段,您还可以在刀片模板中使用策略。让我们快速看看它是如何工作的。
@can('delete', $post)
<!-- Display delete link here... -->
@endcan
在上述情况下,它只会向有权对 Post 模型执行删除操作的用户显示删除链接。
这就是您可以使用的策略概念,在授权模型或资源时它非常方便,因为它允许您将授权逻辑分组在一个地方。
只需确保您不会将门和策略一起用于模型的相同操作,否则会产生问题。这就是我今天的内容,今天就到此为止!
结论
今天,Laravel 授权占据了我文章的中心位置。在文章的开头,我介绍了 Laravel 授权、网关和策略的主要要素。
接下来,我们创建了自定义门和策略,以了解它在现实世界中的工作原理。我希望您喜欢这篇文章,并在 Laravel 环境中学到了一些有用的东西。
对于刚刚开始使用 Laravel 或希望通过扩展来扩展您的知识、网站或应用程序的人,我们在 Envato Market 上提供了多种可供您学习的内容。
以上就是Laravel中的门和策略的详细内容,更多请关注其它相关文章!
Php