美文网首页
Laravel 策略类的使用

Laravel 策略类的使用

作者: empyy | 来源:发表于2019-01-09 14:13 被阅读0次

[文档:https://laravel-china.org/docs/laravel/5.5/authorization/1310](https://laravel-china.org/docs/laravel/5.5/authorization/1310)

## 创建策略:

策略是在特定模型或者资源中组织授权逻辑的类。

例如:给用户的操作创建一个策略里

```

php artisan make:policy UserPolicy

```

该命令会创建一个文件:app/Policies/UserPolicy.php

make:policy 会生成空的策略类。

==如果希望生成的类包含基本的「CRUD」策略方法, 可以在使用命令时指定 --model 选项:==

```

php artisan make:policy UserPolicy --model=User

```

如下:

```

<?php

namespace App\Policies;

use App\User;

use Illuminate\Auth\Access\HandlesAuthorization;

class UserPolicy

{

    use HandlesAuthorization;

    /**

    * Determine whether the user can view the model.

    *

    * @param  \App\User  $user

    * @param  \App\User  $model

    * @return mixed

    */

    public function view(User $user, User $model)

    {

        //

    }

    /**

    * Determine whether the user can create models.

    *

    * @param  \App\User  $user

    * @return mixed

    */

    public function create(User $user)

    {

        //

    }

    /**

    * Determine whether the user can update the model.

    *

    * @param  \App\User  $user

    * @param  \App\User  $model

    * @return mixed

    */

    public function update(User $user, User $model)

    {

        //

    }

    /**

    * Determine whether the user can delete the model.

    *

    * @param  \App\User  $user

    * @param  \App\User  $model

    * @return mixed

    */

    public function delete(User $user, User $model)

    {

        //

    }

}

```

## 注册策略

一旦该授权策略存在,需要将它进行注册。新的 Laravel 应用中包含的 AuthServiceProvider 包含了一个 policies 属性,可将各种模型对应至管理它们的授权策略。注册一个策略将引导 Laravel 在授权动作访问指定模型时使用何种策略:

文件:app/Providers/AuthServiceProvider.php

```

<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider

{

    /**

    * The policy mappings for the application.

    *

    * @var array

    */

    protected $policies = [

        'App\Model' => 'App\Policies\ModelPolicy',

        'App\User' => 'App\Policies\UserPolicy',//注册策略类

        Post::class => PostPolicy::class,

    ];

    /**

    * Register any authentication / authorization services.

    *

    * @return void

    */

    public function boot()

    {

        $this->registerPolicies();

        //

    }

}

```

## 编写策略

### 策略方法

一旦授权策略被生成且注册,我们就可以为授权的每个动作添加方法。

```

<?php

namespace App\Policies;

use App\User;

use Illuminate\Auth\Access\HandlesAuthorization;

class UserPolicy

{

    use HandlesAuthorization;

    /**

    * Determine whether the user can view the model.

    *  判断用户列表能否被用户查询

    * @param  \App\User $user 当前登录的用户

    * @param  \App\User $model 操作的对象

    * @return mixed

    */

    public function view(User $user, User $model)

    {

        //

        return $user->can('manage_users');

    }

    /**

    * Determine whether the user can create models.

    * 判断是否有权限创建用户

    * @param  \App\User $user 当前登录用户

    * @return mixed

    */

    public function create(User $user)

    {

        //

        return $user->can('manage_users');

    }

    /**

    * Determine whether the user can update the model.

    * 判断是否有权限更新用户:要求拥有用户管理权限或者是用户自己

    * @param  \App\User $user

    * @param  \App\User $model

    * @return mixed

    */

    public function update(User $user, User $model)

    {

        //

        return $user->can('manage_users') || $user->id == $model->id;

    }

    /**

    * Determine whether the user can delete the model.

    * 判断是否有权限删除用户

    * @param  \App\User $user

    * @param  \App\User $model

    * @return mixed

    */

    public function delete(User $user, User $model)

    {

        //

        return $user->can('manage_users');

    }

}

```

## 策略过滤器

对特定用户,你可能希望通过指定的策略授权所有动作。 要达到这个目的,可以在策略中定义一个 before 方法。before 方法会在策略中其它所有方法之前执行,这样提供了一种方式来授权动作而不是指定的策略方法来执行判断。这个功能最常见的场景是授权应用的管理员可以访问所有动作:

创建如下策略类:Policy,并让其他策略类继承此类。

```

<?php

namespace App\Policies;

use App\User;

use Illuminate\Auth\Access\HandlesAuthorization;

class Policy

{

    use HandlesAuthorization;

    /**

    * Create a new policy instance.

    *

    * @return void

    */

    public function __construct()

    {

        //

    }

    public function before(User $user, $ability)

    {

        if ($user->isSuperAdmin()) {

            return true;

        }

    }

}

```

## 使用策略授权动作

### 通过用户模型

Laravel 应用内置的 User 模型包含 2 个有用的方法来授权动作:can 和 cant。can 方法需要指定授权的动作和相关的模型。

如下:ajax请求 权限检验代码

```

    /**

    * 添加

    * @param UserRequest $request

    * @param Result $result

    * @return array

    */

    public function store(UserRequest $request, Result $result)

    {

        if ($request->user()->cant('create', User::class)) {

            return $result->failed('没有权限')->toArray();

        }

        try {

            $data = $request->only(['name', 'username', 'email', 'password', 'status', 'sex', 'bool_admin']);

            $data['password'] = bcrypt($data['password']);

            $user = User::create($data);

            $roles = $request->input('roles') ? $request->input('roles') : [];

            $user->assignRole($roles);

            // 要求:User和配置的 auth.default.guard 对应的provider 使用的 user model 为同一个类

            //(因为 Role 默认的guard为配置)

            $result->succeed($user);

        } catch (\Exception $exception) {

            $result->failed($exception->getMessage());

        }

        return $result->toArray();

    }

    /**

    * 更新

    *

    * @param UserRequest $request

    * @param $id

    * @param Result $result

    * @return array

    */

    public function update(UserRequest $request, $id, Result $result)

    {

        $user = User::find($id);

        if ($request->user()->cant('update', $user)) {

            return $result->failed('没有权限')->toArray();

        }

        $data = $request->only(['name', 'username', 'email', 'password', 'status', 'sex', 'bool_admin']);

        $user->update($data);

        $roles = $request->input('roles') ? $request->input('roles') : [];

        $user->syncRoles($roles);

        $result->succeed($user);

        return $result->toArray();

    }

```

### 视图权限控制

如下:创建用户的页面权限-若无权限抛出异常 AuthorizationException

```

/**

    * 新增页面

    * @param User $user

    * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View

    * @throws \Illuminate\Auth\Access\AuthorizationException

    */

    public function create(User $user)

    {

        $this->authorize('create', User::class);

        $roles = Role::get()->pluck('name', 'remarks')->toArray();

        $userRoles = [];

        return $this->backend_view('users.create_edit', compact('user', 'roles', 'userRoles'));

    }

```

处理抛出的授权异常:在app/Exceptions/Handler.php中判断异常类型,若是授权异常,则跳转到无权限页面

```

/**

    * Render an exception into an HTTP response.

    * @param \Illuminate\Http\Request $request

    * @param Exception $exception

    * @return \Illuminate\Http\RedirectResponse|\Symfony\Component\HttpFoundation\Response

    */

    public function render($request, Exception $exception)

    {

        if ($exception instanceof AuthorizationException) {

            return redirect()->guest(route('admin.permission-denied'));

        }

        return parent::render($request, $exception);

    }

```

## 通过控制器辅助函数

除了在 User 模型中提供辅助方法外,Laravel 也为所有继承了 App\Http\Controllers\Controller 基类的控制器提供了一个有用的 authorize 方法。和 can 方法类似,这个方法接收需要授权的动作和相关的模型作为参数。如果动作不被授权,authorize 方法会抛出 Illuminate\Auth\Access\AuthorizationException 异常,然后被 Laravel 默认的异常处理器转化为带有 403 状态码的 HTTP 响应:

```

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

    */

    public function update(Request $request, Post $post)

    {

        $this->authorize('update', $post);

        // 当前用户可以更新博客...

    }

}

```

遇见异常:

```

protected function prepareException(Exception $e)

    {

        if ($e instanceof ModelNotFoundException) {

            $e = new NotFoundHttpException($e->getMessage(), $e);

        } elseif ($e instanceof AuthorizationException) {

            $e = new AccessDeniedHttpException($e->getMessage(), $e);

        } elseif ($e instanceof TokenMismatchException) {

            $e = new HttpException(419, $e->getMessage(), $e);

        }

        return $e;

    }

    //"This action is unauthorized."

```

原因:未注册用户的策略类UserPolicy 到 app/Providers/AuthServiceProvider.php (注意:每个策略类都要和对应的model绑定)

解决方案:

```

<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider

{

    /**

    * The policy mappings for the application.

    *

    * @var array

    */

    protected $policies = [

        'App\Model' => 'App\Policies\ModelPolicy',

        'App\User' => 'App\Policies\UserPolicy',//注册策略类

    ];

    /**

    * Register any authentication / authorization services.

    *

    * @return void

    */

    public function boot()

    {

        $this->registerPolicies();

        //

    }

}

```

相关文章

网友评论

      本文标题:Laravel 策略类的使用

      本文链接:https://www.haomeiwen.com/subject/gztgrqtx.html