The content of this article is about the implementation of ACL user authorization and permission checking functions in the Laravel 5.1 framework. It has certain reference value and I hope it can help friends in need.
1. Introduction
The out-of-the-box authentication function provided by Laravel makes user registration, login, logout and password reset convenient and simple.
But if you need to control access to specific parts of the site, or allow non-administrators to open/close specific pages, or ensure that certain users can only edit things they publish (such as articles), then you need to introduce Use a tool like BeatSwitch Lock or manually write such a function yourself. We call such a feature ACL: Access Control Lists (Access Control Lists), which are used to define a user's permissions to operate or view specific things based on their user record attributes.
Fortunately, starting from Laravel 5.1.11, Laravel provides out-of-the-box authorization functions to achieve the above requirements. We no longer need to do any additional work, just use it.
Note: Before starting this section, please refer to the upgrade guide to upgrade Laravel to Laravel 5.1.11, otherwise related functions will not be implemented.
2. What can be done?
The out-of-the-box ACL provided by Laravel is called Gate (this is not a product name like Spark, but just the name of a class and facade).
Using the Gate class (injection or using the Gate facade) allows us to easily check whether a certain user (currently logged in user or specified user) is allowed to operate specific things. The check code is as follows:
if (Gate::denies('update-post', $post)) { abort(403); }
Put this code in the controller, it will use the defined rule update-post to check whether the currently authenticated user has permission to update the specified article.
You can also use Gate::allows, which is the opposite of the denies method, and can also be used through @can in the Blade view template, and there are many more, let's take a look next.
3. How to use?
Laravel ACL is built on the concept of "permissions". Permissions include a key (such as update-post) and a closure that returns true or false (parameters can be passed in).
3.1 Define permissions
Let us define the user update post permission update-post in AuthServiceProvider as follows:
<?php namespace App\Providers; use Illuminate\Contracts\Auth\Access\Gate as GateContract; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; class AuthServiceProvider extends ServiceProvider{ /** * 注册应用所有的认证/授权服务. * * @param \Illuminate\Contracts\Auth\Access\Gate $gate * @return void */ public function boot(GateContract $gate) { parent::registerPolicies($gate); $gate->define('update-post', function ($user, $post) { return $user->id === $post->user_id; }); } }
As you can see, The first parameter that defines the permission closure is the specified user. If the current user does not pass login authentication, Gate will return false by itself.
Of course, in addition to closures, you can also replace closures with class methods as the second parameter, which will be parsed in the container:
$gate->define( 'update-post', 'PostPolicy@update');
3.2 Check permissions through the Gate facade
Gate provides the following methods to check permissions: check, The functions of allows and denies, check and allows are exactly the same, while the functions of denies and allows are opposite.
If you use the facade to check permissions, you do not need to pass the user instance. The Gate facade will automatically pass in the current user:
if (Gate::denies('update-post', $post)) { abort(403); }
If you define multiple parameters in the permissions:
Gate::define('delete-comment', function ($user, $post, $comment) { // });
The checking method is as follows:
if (Gate::allows('delete-comment', [$post, $comment])) { // }
If you want to check whether a non-currently authenticated user has permission to operate, the calling method is as follows:
if (Gate::forUser($user)->allows('update-post', $post)) { // }
3.3 Use Gate injection to check permissions
As always, you can inject the Gate class instead of using its facade. The injected class is the same as you in the AuthServiceProvider - Illuminate\Contracts\Auth\Access\Gate:
public function somethingResolvedFromContainer(Gate $gate) { if ($gate->denies('update-post')) { // etc. } }
3.4 Use the User model to check permissions
Laravel's App\User model now uses the Authorizabletrait, so you can use the can and cannot methods it provides, which correspond to the Gate's allows and denies methods respectively.
So we can also use the User model to check permissions:
public function update(Request $request, $id) { $post = Post::findOrFail($id); if ($request->user()->cannot('update-post', $post)) { abort(403); } // 更新文章... }
3.5 Check permissions in Blade
You can use @can in Blade Command to check permissions:
<a href="/post/{{ $post->id }}">查看文章</a> @can('update-post', $post) <a href="/post/{{ $post->id }}/edit">编辑文章</a> @endcan
The opposite is the @else command:
@can('update-post', $post) <!-- The Current User Can Update The Post --> @else <!-- The Current User Can't Update The Post --> @endcan
3.6 Abort permission check
If you are an administrator or super What if the user has all permissions? Or what if you want to temporarily switch the ACL logic for users?
The before method provided by Gate allows you to return before performing other checks under certain circumstances, without further checking permissions:
$gate->before(function ($user, $ability) { if ($user->last_name === 'Stauffer') { return true; } });
Or when using the user's own:
$gate->before(function ($user, $ability) { if ($user->isOwner()) { return true; } });
3.7 Policy class
As application logic becomes more and more complex, more and more permissions need to be processed. It is obviously not a wise idea to define all permissions in AuthServiceProvider. Therefore, Laravel introduced strategy classes. Strategy classes are some native PHP classes. Similar to how controllers group routes based on resources, strategy classes manage permissions in groups based on resources.
Generate policy class
You can use the following Artisan command to generate the PostPolicy policy class:
php artisan make:policy PostPolicy
The generated policy class is located in the app/Policies directory.
Then we can register the policy class in the policies attribute of AuthServiceProvider:
protected $policies = [ Post::class => PostPolicy::class, ];
Below we edit the PostPolicy as follows:
<?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; } }
Note: All policy classes are parsed through the service container , which means you can type-hint any dependencies in the constructor of your strategy class and they will be automatically injected.
Check Strategy
如果为某个资源类型定义了策略类,Gate将会使用第一个参数来判断检查策略类上的哪个方法。
因此,要检查是否有权限更新某篇文章,只需要传入文章实例和update权限:
<?php namespace App\Http\Controllers; use Gate; use App\User; use App\Post; use App\Http\Controllers\Controller; class PostController extends Controller{ /** * 更新给定文章 * * @param int $id * @return Response */ public function update($id) { $post = Post::findOrFail($id); if (Gate::denies('update', $post)) { abort(403); } // 更新文章... } }
当然也可以使用User模型和Blade指令检查权限。
此外,Laravel还提供了一个全局帮助函数policy来检查权限:
if (policy($post)->update($user, $post)) { // }
3.8 控制器授权
由于大多数授权都会在检查权限失败的情况下退出控制器方法,因此在控制器中检查权限有一条捷径(AuthorizesRequeststrait提供,该trait在基类控制器Controller中被使用):
<?php namespace App\Http\Controllers; use App\Post; use App\Http\Controllers\Controller; class PostController extends Controller{ /** * 更新给定文章 * * @param int $id * @return Response */ public function update($id) { $post = Post::findOrFail($id); $this->authorize('update', $post); // 更新文章... } }
和我们上面的例子一样,如果授权失败会抛出403错误。
最后,如果你的控制器方法名和策略类中的方法名相同,例如都是update,则可以省略authorize的第一个参数:
public function update($id){ $post = Post::findOrFail($id); $this->authorize($post); // 更新文章... }
此外,AuthorizesRequests也提供了对非当前认证用户权限检查的支持:
$this->authorizeForUser($user, 'update', $post);
相关文章推荐:
Laravel 5.1框架中如何创建自定义Artisan控制台命令
相关课程推荐:
The above is the detailed content of Implementation of ACL user authorization and permission checking functions in Laravel 5.1 framework. For more information, please follow other related articles on the PHP Chinese website!