首頁  >  文章  >  php框架  >  Laravel 5.1框架中的ACL使用者授權與權限檢查功能的實現

Laravel 5.1框架中的ACL使用者授權與權限檢查功能的實現

不言
不言原創
2018-07-31 11:48:452261瀏覽

這篇文章給大家分享的內容是關於Laravel 5.1框架中的ACL使用者授權及權限檢查功能的實現,有一定的參考價值,希望可以幫助到有需要的朋友。

1、引言

Laravel提供的開箱即用的認證功能使得使用者註冊、登入、登出和密碼重設變得便捷和簡單。

但是如果你需要控制存取網站特定部分,或讓非管理員開啟/關閉特定頁面,又或確保某些使用者只能編輯自己發佈的東西(如文章),那麼你就需要引入類似BeatSwitch Lock這樣的工具或是自己手動寫這樣的功能。我們將這樣的功能稱之為ACL:Access Control Lists(存取控制清單),用於定義使用者基於其使用者記錄屬性操作或查看特定事物的權限。

幸運的是,從Laravel 5.1.11開始,Laravel提供了開箱即用的授權功能用於實現上述需求,我們不再需要做任何額外工作,用就是了。

附註:在開始本節之前,請參考升級指南將Laravel升級到Laravel 5.1.11,否則無法實現相關功能。

2、能做什麼?

Laravel提供的開箱即用的ACL被稱為Gate(這並不是類似Spark的產品名稱,而只是一個類別和門面的名稱)。

使用Gate類別(注入或使用Gate門面)讓我們可以輕鬆檢查某個使用者(目前登入使用者或指定使用者)是否允許操作特定事物。檢查程式碼如下:

if (Gate::denies('update-post', $post)) {
    abort(403);
}

將這段程式碼放到控制器中,它將會使用定義好的規則update-post來檢查目前認證使用者是否有權限更新指定文章。

你也可以使用Gate::allows,該方法與denies方法相對,還可以在Blade視圖模板中透過@can來使用,還有更多更多,讓我們接下來一窺究竟。

3、如何使用?

Laravel ACL建立在「權限」概念之上,權限包含一​​個鍵(例如update-post)和一個傳回true或false的閉包(可傳入參數)。

3.1 定義權限

讓我們在AuthServiceProvider中定義使用者更新文章權限update-post如下:

<?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(&#39;update-post&#39;, function ($user, $post) {
            return $user->id === $post->user_id;
        });
    }
}

正如你所看到的,定義權限閉包的第一個參數是指定用戶,如果目前用戶沒有通過登入認證,Gate將會自定傳回false。

當然,除了閉包之外,還可以透過類別方法作為第二個參數來取代閉包,該類別會在容器中解析:

$gate->define( 'update-post', 'PostPolicy@update');

#3.2 透過Gate門面檢查權限

Gate提供以下方法進行權限檢查:check、 allows和denies,check和allows功能用法完全一樣,而denies和allows功能相反。

如果你使用門面檢查權限,則不需要傳遞使用者實例,Gate門面會自動將目前使用者傳遞進來:

if (Gate::denies(&#39;update-post&#39;, $post)) {       
    abort(403);
}

如果你在權限中定義了多個參數:

Gate::define(&#39;delete-comment&#39;, function ($user, $post, $comment) {
    //
});

則檢查方法如下:

if (Gate::allows(&#39;delete-comment&#39;, [$post, $comment])) {
    //
}

如果你想檢查非目前認證使用者是否有權限操作,呼叫方法如下:

if (Gate::forUser($user)->allows(&#39;update-post&#39;, $post)) {
    //
}

3.3 使用Gate注入檢查權限

和以往一樣,可以注入Gate類別而不是使用其門面,注入的類別和你在AuthServiceProvider中一樣-Illuminate\Contracts\Auth\Access\Gate:

public function somethingResolvedFromContainer(Gate $gate)
{
    if ($gate->denies(&#39;update-post&#39;)) {
        // etc.
    }
}

3.4 使用User模型檢查權限

Laravel的App\User模型現在使用了Authorizabletrait,因此可以使用其提供的can和cannot方法,分別對應Gate的allows和denies方法。

所以我們也可以使用User模型來檢查權限:

public function update(Request $request, $id)
{
    $post = Post::findOrFail($id);
    if ($request->user()->cannot(&#39;update-post&#39;, $post)) {
        abort(403);
    }
    // 更新文章...
}

3.5 在Blade中檢查權限

你可以在Blade中使用@can指令來檢查權限:

<a href="/post/{{ $post->id }}">查看文章</a>
@can(&#39;update-post&#39;, $post)
    <a href="/post/{{ $post->id }}/edit">编辑文章</a>
@endcan

與之相對的是@else指令:

@can(&#39;update-post&#39;, $post)
    <!-- The Current User Can Update The Post -->
@else
    <!-- The Current User Can&#39;t Update The Post -->
@endcan

3.6 中止權限檢查

如果是管理員或超級使用者擁有所有權限怎麼做?或者你想要為使用者臨時切換ACL邏輯又該如何?

Gate提供的before方法允許你在一些特定情況下在執行其他檢查之前就返回,不再往下檢查權限:

$gate->before(function ($user, $ability) {
    if ($user->last_name === &#39;Stauffer&#39;) {
        return true;
    }
});

或使用使用者自己的時候:

$gate->before(function ($user, $ability) {
    if ($user->isOwner()) {
        return true;
    }
});

3.7 策略類別

隨著應用程式邏輯越來越複雜,要處理的權限越來越多,將所有權限定義在AuthServiceProvider顯然不是一個明智的做法,因此Laravel引入了策略類,策略類是一些原生的PHP類,和控制器基於資源對路由進行分組類似,策略類基於資源對權限進行分組管理。

產生策略類別

可以使用以下Artisan指令產生PostPolicy策略類別:

php artisan make:policy PostPolicy

產生的策略類別位於app/Policies目錄。

然後我們可以在AuthServiceProvider的policies屬性中註冊策略類別:

protected $policies = [
    Post::class => PostPolicy::class,
];

下面我們編輯PostPolicy如下:

<?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;
    }
}

註:所有策略類別都透過服務容器進行解析,這意味著你可以在策略類別的建構函式中類型提示任何依賴,它們將會自動被注入。

檢查策略

如果为某个资源类型定义了策略类,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(&#39;update&#39;, $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(&#39;update&#39;, $post);
        // 更新文章...
    }
}

和我们上面的例子一样,如果授权失败会抛出403错误。

最后,如果你的控制器方法名和策略类中的方法名相同,例如都是update,则可以省略authorize的第一个参数:

public function update($id){
    $post = Post::findOrFail($id);
    $this->authorize($post);
    // 更新文章...
}

此外,AuthorizesRequests也提供了对非当前认证用户权限检查的支持:

$this->authorizeForUser($user, &#39;update&#39;, $post);

相关文章推荐:

Laravel 5.1框架中如何创建自定义Artisan控制台命令

相关课程推荐:

2017年最新的五个Laravel视频教程推荐

以上是Laravel 5.1框架中的ACL使用者授權與權限檢查功能的實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn