Laravel 中的 Middleware vs Guards vs Gates/Policies 有什么区别
What is the difference between Middleware vs Guards vs Gates/Policies in Laravel
任何人都可以帮助我理解 when/how 使用其中的每一个吗?
门用于添加登录用户访问的逻辑
但策略用于在模型访问级别
中添加逻辑
门的例子
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
https://laravel.com/docs/8.x/authorization#writing-gates
在这里你可以在 gate 中看到你的 gettin $user
作为回调,所以它用于用户访问 gate
政策示例
运行
php artisan make:policy PostPolicy --model=Post
<?php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
/**
* Determine if the given post can be updated by the user.
*
* @param \App\Models\User $user
* @param \App\Models\Post $post
* @return bool
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
https://laravel.com/docs/8.x/authorization#generating-policies
在这里你可以看到 PostPolicy
正在获取 2 个参数 $user
和 $post
这是模型级访问
用于添加登录用户访问逻辑的Gate
用于在模型访问级别添加逻辑的策略
我也想知道这个问题,经过一些阅读,这是我得出的结论:
中间件
通常运行在路由上(但您也可以运行它在控制器方法上)并且可以用于过滤或检查传入请求.
一个示例是 auth
,它确定尝试请求特定路线的人是否已通过系统身份验证(登录)。另一个示例是检查请求是否具有特定的 header(例如,如果您想检查应用程序是否正在发送 X-MYAPP-CUSTOMHEADER
header 或其他内容)
如前所述,中间件可以在路由(例如 web.php
或 api.php
)或控制器中定义。
web.php中的示例:
// Get all the posts, but only if the user has signed in to the website
Route::get('/posts', [PostController::class, 'index'])->middleware('auth');
PostController.php
中的示例:
public function __construct() {
// Apply the `auth` middleware to every function in this controller
$this->middleware('auth');
// Apply the `signed` middleware, but only to the functions `download` and `delete`
$this->middleware('signed', ['only' => ['download', 'delete']]);
}
盖茨
门是在您的 AuthServiceProvider.php
文件(在 App\Providers
文件夹中)中定义的函数,并且 指定允许用户做什么以及不允许他们做什么。例如:
Gate::define('delete-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
然后在您的 PostController
的 delete
方法中:
public function delete(Request $request, Post $post)
{
if (Gate::denies('delete-post', $post)) { // Returns true if `$post->user_id` is not the same as `$user->id` (a.k.a the user is not allowed to delete this post)
abort(403);
}
$post->delete();
}
您还可以在 blade 模板中使用一些辅助方法:
@can('delete-post', $post)
<!-- Show a link to the delete page here -->
@endcan
(我在下面对此进行了扩展)
守卫
Guards 是一种指定用户如何针对请求进行身份验证的方法。
在我正在进行的项目中,我的 API 路由上有一个 jwt
(JSON Web 令牌)守卫。这意味着当我执行类似 auth()->attempt(['username' => 'test', 'password' => 'test']);
的操作时,auth()
函数将尝试使用 jwt
守卫对我进行身份验证。
auth.php
中指定了要使用的守卫。我的目前看起来像这样:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users'
],
],
所以在这种情况下,通过浏览器传入的请求将在登录时分配 session,而通过 API 调用传入的请求将需要获取/提供令牌进行验证。两者都会在验证时查找 users
table 以检查用户名/密码。
您可以通过 auth()
调用指定要使用的守卫:
auth('api')->attempt(['api_key' => 'abc1234'])
(还有旁注,我被这个问题抓住了,因为我想知道为什么 auth()->user()
没有返回当前用户,那是因为 web
是默认的守卫,我正在尝试获取通过 api
进行身份验证的用户,因此请务必明确说明哪个守卫!)
政策
政策与门类似,但只是适用于特定模型并存储在自己的文件中(在App\Policies
中)
您可以使用 php artisan make:policy PostPolicy -m Post
创建一个。它将创建一个名为 PostPolicy.php
的文件,该文件将创建一堆函数:
viewAny // Can the user even look at this model? If no, they'll be denied for all the below methods
view // Can the user look at the specified Post?
create // Can they create a new Post
update // Can they edit / update the specified Post?
delete // Can they (soft) delete the specified Post?
restore // Can they restore the specified (soft) deleted Post?
forceDelete // Can they force delete the specified Post?
典型函数如下所示:
public function viewAny(User $user)
{
// If this returns true, then the other methods will be evaluated.
return $user->can_view_posts;
}
public function forceDelete(User $user, Post $post)
{
// If this returns true, then the user can force delete the post.
// This depends on viewAny being true
return $post->user_id == $user->id;
}
需要注意的一点是,viewAny
与“查看全部”不同!将 viewAny
视为建筑物的前门。如果 viewAny
为真,您可以进入大厅,但您不能查看任何房间,除非特定房间的 view
也为真。
我相信您也可以在 blade 模板中使用 @can
策略:
@can('forceDelete', $post)
<!-- Show button to force delete a post here -->
@endcan
反之亦然:
@cannot('view', $post)
<!-- Show a greyed out button or something -->
@cannot
以及用于检查多个权限的@canany
:
@canany(['edit', 'delete'])
<!-- Show something if the user can edit OR delete -->
@endcanany
结论
我希望这对您有用。在阅读这篇文章时,我当然学到了很多东西。这比我想象的要多得多,所以值得查看 Laravel 文档,因为我在某些事情上可能是正确的,但在其他事情上可能会偏离。
任何人都可以帮助我理解 when/how 使用其中的每一个吗?
门用于添加登录用户访问的逻辑
但策略用于在模型访问级别
中添加逻辑门的例子
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
https://laravel.com/docs/8.x/authorization#writing-gates
在这里你可以在 gate 中看到你的 gettin $user
作为回调,所以它用于用户访问 gate
政策示例
运行
php artisan make:policy PostPolicy --model=Post
<?php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
/**
* Determine if the given post can be updated by the user.
*
* @param \App\Models\User $user
* @param \App\Models\Post $post
* @return bool
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
https://laravel.com/docs/8.x/authorization#generating-policies
在这里你可以看到 PostPolicy
正在获取 2 个参数 $user
和 $post
这是模型级访问
用于添加登录用户访问逻辑的Gate 用于在模型访问级别添加逻辑的策略
我也想知道这个问题,经过一些阅读,这是我得出的结论:
中间件
通常运行在路由上(但您也可以运行它在控制器方法上)并且可以用于过滤或检查传入请求.
一个示例是 auth
,它确定尝试请求特定路线的人是否已通过系统身份验证(登录)。另一个示例是检查请求是否具有特定的 header(例如,如果您想检查应用程序是否正在发送 X-MYAPP-CUSTOMHEADER
header 或其他内容)
如前所述,中间件可以在路由(例如 web.php
或 api.php
)或控制器中定义。
web.php中的示例:
// Get all the posts, but only if the user has signed in to the website
Route::get('/posts', [PostController::class, 'index'])->middleware('auth');
PostController.php
中的示例:
public function __construct() {
// Apply the `auth` middleware to every function in this controller
$this->middleware('auth');
// Apply the `signed` middleware, but only to the functions `download` and `delete`
$this->middleware('signed', ['only' => ['download', 'delete']]);
}
盖茨
门是在您的 AuthServiceProvider.php
文件(在 App\Providers
文件夹中)中定义的函数,并且 指定允许用户做什么以及不允许他们做什么。例如:
Gate::define('delete-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
然后在您的 PostController
的 delete
方法中:
public function delete(Request $request, Post $post)
{
if (Gate::denies('delete-post', $post)) { // Returns true if `$post->user_id` is not the same as `$user->id` (a.k.a the user is not allowed to delete this post)
abort(403);
}
$post->delete();
}
您还可以在 blade 模板中使用一些辅助方法:
@can('delete-post', $post)
<!-- Show a link to the delete page here -->
@endcan
(我在下面对此进行了扩展)
守卫
Guards 是一种指定用户如何针对请求进行身份验证的方法。
在我正在进行的项目中,我的 API 路由上有一个 jwt
(JSON Web 令牌)守卫。这意味着当我执行类似 auth()->attempt(['username' => 'test', 'password' => 'test']);
的操作时,auth()
函数将尝试使用 jwt
守卫对我进行身份验证。
auth.php
中指定了要使用的守卫。我的目前看起来像这样:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users'
],
],
所以在这种情况下,通过浏览器传入的请求将在登录时分配 session,而通过 API 调用传入的请求将需要获取/提供令牌进行验证。两者都会在验证时查找 users
table 以检查用户名/密码。
您可以通过 auth()
调用指定要使用的守卫:
auth('api')->attempt(['api_key' => 'abc1234'])
(还有旁注,我被这个问题抓住了,因为我想知道为什么 auth()->user()
没有返回当前用户,那是因为 web
是默认的守卫,我正在尝试获取通过 api
进行身份验证的用户,因此请务必明确说明哪个守卫!)
政策
政策与门类似,但只是适用于特定模型并存储在自己的文件中(在App\Policies
中)
您可以使用 php artisan make:policy PostPolicy -m Post
创建一个。它将创建一个名为 PostPolicy.php
的文件,该文件将创建一堆函数:
viewAny // Can the user even look at this model? If no, they'll be denied for all the below methods
view // Can the user look at the specified Post?
create // Can they create a new Post
update // Can they edit / update the specified Post?
delete // Can they (soft) delete the specified Post?
restore // Can they restore the specified (soft) deleted Post?
forceDelete // Can they force delete the specified Post?
典型函数如下所示:
public function viewAny(User $user)
{
// If this returns true, then the other methods will be evaluated.
return $user->can_view_posts;
}
public function forceDelete(User $user, Post $post)
{
// If this returns true, then the user can force delete the post.
// This depends on viewAny being true
return $post->user_id == $user->id;
}
需要注意的一点是,viewAny
与“查看全部”不同!将 viewAny
视为建筑物的前门。如果 viewAny
为真,您可以进入大厅,但您不能查看任何房间,除非特定房间的 view
也为真。
我相信您也可以在 blade 模板中使用 @can
策略:
@can('forceDelete', $post)
<!-- Show button to force delete a post here -->
@endcan
反之亦然:
@cannot('view', $post)
<!-- Show a greyed out button or something -->
@cannot
以及用于检查多个权限的@canany
:
@canany(['edit', 'delete'])
<!-- Show something if the user can edit OR delete -->
@endcanany
结论
我希望这对您有用。在阅读这篇文章时,我当然学到了很多东西。这比我想象的要多得多,所以值得查看 Laravel 文档,因为我在某些事情上可能是正确的,但在其他事情上可能会偏离。