使用 authorizeResource 简化你的 Resource Controller 用户授权

用户授权

众所周知,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:

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 1
Epona

这个小技巧还是蛮赞的

6年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!