User authorization
allows or
denies method. Note that the current authenticated user does not need to be passed to these methods. Laravel will automatically handle the authenticated user and then pass it to the gete closure function:
if (Gate::allows('update-post', $post)) { // 指定当前用户可以进行更新... } if (Gate::denies('update-post', $post)) { // 指定当前用户不能更新... }If you want to determine whether a specific user has been authorized to access an action, you can use
GateforUser
method in facade:
if (Gate::forUser($user)->allows('update-post', $post)) { // 用户可以更新... } if (Gate::forUser($user)->denies('update-post', $post)) { // 用户不能更新... }Gate interception check Sometimes, you may want to grant all capabilities to a specific user. So you can use the
before method to define a callback that runs before all other authorization checks:
Gate::before(function ($user, $ability) { if ($user->isSuperAdmin()) { return true; } });If the
before callback method returns a non-null result, the result will be considered as inspection results.
after method to define a callback to be executed after each authorization check. However, you cannot modify the result of the authorization check from the
after callback method:
Gate::after(function ($user, $ability, $result, $arguments) { // });is similar to the
before check, if the
after callback returns non null result, the result will be treated as a check result.
Generate Policy
A policy is a class that organizes authorization logic in a specific model or resource. For example, if your application is a blog, then when you create or update the blog, you may have a Post
model and a corresponding PostPolicy
to authorize user actions.
You can use the make:policy
artisan command command in the artisan command
artisan command to generate the policy. The generated policies will be placed in the app/Policies
directory. If this directory does not exist in your application, Laravel will automatically generate it for you:
php artisan make:policy PostPolicy
make:policy
The command will generate an empty policy class. If the class you want to generate contains basic "CRUD" strategy methods, you can specify the --model
option when executing the command:
php artisan make:policy PostPolicy --model=Post
{tip} all Strategies are parsed through Laravel's service container, allowing you to type-hint any required dependencies in the policy constructor and have them injected automatically.
Registering Policy
Once a policy exists, it needs to be registered. The AuthServiceProvider
included in new Laravel applications has a policies
property that maps various models to their policies. Registering a policy will instruct Laravel which policy to use when authorizing actions to access a specified model:
<?php namespace App\Providers; use App\Post;use App\Policies\PostPolicy; use Illuminate\Support\Facades\Gate; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; class AuthServiceProvider extends ServiceProvider{ /** * 应用的策略映射。 * * @var array */ protected $policies = [ Post::class => PostPolicy::class, ]; /** * 注册任意应用认证、应用授权服务 * * @return void */ public function boot() { $this->registerPolicies(); // } }
Policy auto-discovery
As long as the model and policy follow standard Laravel naming By convention, Laravel can automatically discover strategies instead of manually registering model strategies. Specifically, the policy must be located in the Policies
directory under the directory containing the model. So, for example, models can be placed in the app
directory, and policies can be placed in the app/Policies
directory. Additionally, the policy name must match the model name and have the Policy
suffix. Therefore, the User
model will correspond to the UserPolicy
class.
If you want to provide your own policy discovery logic, you can register a custom callback using the Gate::guessPolicyNamesUsing
method. Typically, this method should be called from the boot
method of your application's AuthServiceProvider
:
use Illuminate\Support\Facades\Gate; Gate::guessPolicyNamesUsing(function ($modelClass) { // return policy class name... });
##Writing Strategy##{note} Explicit in
AuthServiceProvider
Any policy that is mapped will take precedence over the auto-discovery policy.
Strategy Methods
Once the authorization policy is registered, you can add methods for each action after authorization. For example, we define an update
method in PostPolicy
, which will determine whether the specified User
can update the specified Post
instance. The
update
method receives User
and Post
instances as parameters and should return true
or false
To indicate whether the user is authorized to update the specified Post
. So in this example, we need to determine whether the user's id
matches the user_id
in the post.
<?php namespace App\Policies;use App\User; use App\Post;class PostPolicy{ /** * 判断该方法能否被用户操作。 * * @param \App\User $user * @param \App\Post $post * @return bool */ public function update(User $user, Post $post) { return $user->id === $post->user_id; } }
You can continue to define additional methods for this authorization policy. For example, you can define the view
or delete
method to authorize multiple behaviors of Post
, and you can also give the custom strategy method a name you like. .
{tip} If you use the
--model
option when generating a strategy in the Artisan console, it will be includedview
,create
,update
anddelete
action methods.
Does not contain model methods
Some policy methods only receive currently authenticated users as parameters, Instead of passing in the authorization-related model instance. The most common application scenario is to authorize the create
action. For example, if you are creating a blog, you may want to first check whether the current user has permission to create it.
When defining a strategy method that does not require passing in a model instance, such as the create
method, it does not receive a model instance as a parameter. You should define this method to only accept authorized users as parameters.
/** * 判断用户是否可以创建请求。 * * @param \App\User $user * @return bool */ public function create(User $user){ // }
Guest User
By default, if the incoming HTTP request is not initiated by an authenticated user , then all gates and strategies will automatically return false
. However, you can allow these authorization checks to be passed into your gates and policies by declaring an "optional" type hint or providing a null
default value for the user parameter definition:
<?php namespace App\Policies; use App\User;use App\Post;class PostPolicy{ /** * 判断用户是否能更新指定帖子。 * * @param \App\User $user * @param \App\Post $post * @return bool */ public function update(?User $user, Post $post) { return $user->id === $post->user_id; } }
Policy Filter
For a specific user, you may want to authorize all actions through a specified policy. To achieve this goal, you can define a before
method in the strategy. The before
method will be executed before all other methods in the policy, thus providing a way to authorize actions other than the specified policy method to perform judgment. The most common scenario for this feature is to authorize the application's administrator to have access to all actions:
public function before($user, $ability){ if ($user->isSuperAdmin()) { return true; } }
If you want to deny all authorizations to a user, you should return ## in the before
method #false . If the return value is
null, then authorization will fail in this policy.
{note} Thebefore
method of a strategy class will not be called if the class does not contain a method matching the function name being checked.
Laravel’s built-in
User model contains two useful methods for authorizing actions: can
and cant
. This can
method needs to specify the authorized action and related model. For example, to determine whether a user is authorized to update the specified Post
model:
If the "if ($user->can('update', $post)) {
//
}
", can The method automatically calls the appropriate strategy and returns a boolean value. If no strategy is registered to this model, the can
method will attempt to call a closure-based Gate that matches the specified action name.
Remember that some actions, such as
create, do not require specifying a model instance. In this case, pass a class name to the can
method. This class name will be used to determine which policy authorization action to use: use App\Post;if ($user->can('create', Post::class)) {
// 执行相关策略中的 "create" 方法...
}
Laravel includes A middleware that can authorize actions before the request reaches the route or controller. By default, the
Illuminate\Auth\Middleware\Authorize middleware is assigned to the can
key in your App\Http\Kernel
class. Let us use an example of an authorized user updating a blog to explain the use of the can
middleware:
In this example, we passed the use App\Post;Route::put('/post/{post}', function (Post $post) {
// 当前用户可以进行更新操作...
})->middleware('can:update,post');
middleware two parameters. The first parameter is the name of the action that requires authorization, and the second parameter is the routing parameter we want to pass to the policy method. In this case, we use "implicit route binding" and a Post
model is passed to the strategy method. If the user is not authorized to access the specified action, this middleware will generate an HTTP response with the 403
status code.
Actions that do not require a specified model
Similarly, some actions like create
may not require a model instance. In this case, you can pass a class name to the middleware. When authorizing this action, this class name will be used to determine which policy to use:
Route::post('/post', function () { // 当前用户可以进行创建操作... })->middleware('can:create,App\Post');
Through the controller helper function
In addition to providing helper methods in the User
model, Laravel also provides a useful for controllers that inherit the
App\Http\Controllers\Controller base class. authorize
method. Just like the can
method, this method needs to receive the action you want to authorize and the related model as parameters. If this action is not authorized, the authorize
method will throw an exception of Illuminate\Auth\Access\AuthorizationException
, and then Laravel's default exception handler will convert this exception into an exception with 403
HTTP response status code.
<?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); // 当前用户可以更新博客... } }
No need to specify the action of the model
As discussed before, some actions, such as create
, do not need to specify the action of the model instance . In this case, you can pass a class name to the authorize
method. When authorizing this action, this class name will be used to determine which policy to use:
/** * 创建一个新的博客 * * @param Request $request * @return Response * @throws \Illuminate\Auth\Access\AuthorizationException */ public function create(Request $request){ $this->authorize('create', Post::class); // 当前用户可以新建博客... }
Authorization Resource Controller
If you are using a resource controller, then You can use the authorizeResource
method in the controller constructor. This method will attach the appropriate can
middleware to the corresponding method of the resource controller.
authorizeResource
The method receives the template class name as the first parameter and the name of the route/request parameter containing the model ID as its second parameter:
<?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'); } }
##Through Blade TemplatesWhen writing Blade templates, you may want only specific portions of the page to Displayed to users authorized to access the specified action. For example, you might want to display updated forms only to users who have permission to update their blog. In this case, you can use a series of instructions such as{Tip} You can use the
make:policy
command with the--model
option to quickly generate a policy class based on a given model:php artisan make:policy PostPolicy --model=Post
.
@can and
@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 --> @endcannotThese instructions are written
@if and
@unless Shortcut to statement. The
@can and
@cannot statements are converted into the following statements respectively:
@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
Model-independent actions
As with most other authorization methods, if the action does not require a model instance, you can pass the class name to @ can
and @ cannot
Instructions:
@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