使用 authorizeResource 簡化你的 Resource Controller 使用者授權

young發表於2017-05-13

使用者授權

眾所周知,Laravel 在5.1版本的時候引入了使用者授權系統。使用使用者授權系統有兩種方式,gates 和策略。他們具體的區別 文件裡說的很詳細了,這裡不再闡述。一般我們都會使用策略來驗證 Resource Controller ,類似如下的程式碼:

/**
 * 新建部落格
 *
 * @param  Request  $request
 * @return Response
 */
public function create(Request $request)
{
    $this->authorize('create', Post::class);

    // 當前使用者可以新建部落格...
}

或者直接使用$this->authorize(Post::class) 不指明驗證的許可權,Laravel 會直接根據函式名來判斷使用何種許可權。雖然已經很方便了,但是發現了沒有我們還是需要在每一個控制器裡面都寫一次$this->authorize(Post::class)來進行許可權判斷。有沒有覺得很繁瑣?其實我們有更好的解決辦法!

authorizeResource

解決辦法就是我們只需要在控制器的construct函式裡面加一句:

    /**
     * PostController constructor.
     */
    public function __construct()
    {
        $this->authorizeResource(Post::class);
    }

Done,每一個控制器方法的邏輯在執行前都會自動進行許可權判斷,不通過就會自動返回403錯誤。What?很神奇有沒有,是不是感覺和 Laravel 這個框架一樣,像一個魔術。其實authorizeResource這個函式內部使用了中介軟體驗證這一特性來完成自動鑑權。通過讀取resourceAbilityMap返回的許可權對映陣列為每一個控制器方法新增相應的許可權驗證中介軟體。具體的原始碼我們在此不做分析,有興趣的同學可以自行研究。不過使用這個特性我們還需要注意幾個地方。

提示

第一個就是resourceAbilityMap函式。我們前面提過,Laravel 會通過讀取這個函式返回的許可權對映陣列,來找到每個控制器方法相應的許可權驗證函式。預設的resourceAbilityMap函式長這樣:

        /**
     * Get the map of resource methods to ability names.
     *
     * @return array
     */
    protected function resourceAbilityMap()
    {
        return [
            'show' => 'view',
            'create' => 'create',
            'store' => 'create',
            'edit' => 'update',
            'update' => 'update',
            'destroy' => 'delete',
        ];
    }

可以看到每一個 Resouce Controller 方法都對應著相應的許可權驗證函式名。如果你的控制器裡有預設資源控制器不存在的方法,你就需要在控制器裡面 override 這個函式。如:

protected function resourceAbilityMap()
{
    return [
        'index'      => 'list',
        'datatables' => 'list', // Here, a new resource method.
        'show'       => 'view',
        'create'     => 'create',
        'store'      => 'create',
        'edit'       => 'update',
        'update'     => 'update',
        'destroy'    => 'delete',
    ];
}

第二個需要注意的地方是 v5.4.20 版本之前,使用resourceAbilityMap新增的自定義驗證函式是必須指定模型例項的,很顯然這是不合理的。所以 v5.4.20 之後你可以在控制器裡定義methodsWithoutModels函式來返回不需要指定模型例項的方法。如:

protected function resourceMethodsWithoutModels()
{
   // This new resource method doesn't need any parameter, so you can add it here.
    return ['index', 'datatables', 'create', 'store'];
}

新版本的改進是不是讓你覺得這個方法使你的使用者授權更加如魚得水?其實不光是資源控制器,一般的控制器也能使用這個辦法來進行使用者授權,來使你的程式碼更簡潔,美觀。

推薦

最後,如果有同學對使用者授權這一方面還是弄得不是很清楚的,推薦可以讀一讀 Laravel Main Contributor-Joseph Silber 的這篇關於使用者授權的文章。還有他的bouncer,真心是 Laravel 上用過最舒服也最強大的許可權控制系統擴充套件包。

寫在最後

其實 Laravel 有好多東西是文件裡沒有提到的,很多 Laravel 使用者也會在 twitter 上分享一些很巧妙的小技巧。以後我會發一些能讓你醍醐灌頂的小技巧在專欄裡,希望你能喜歡 :tada:

相關文章