iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 26
1
Software Development

從零開始的Laravel RESTful api系列 第 26

Day 26 : Policy authorization

上一篇提到有違和感的部份就是權限問題,在 post 的部份,update 和 destroy 這兩個方法其實應該要有所限制,也就是除了 admin 之外,只有該貼文的擁有者才能夠採取該方法。不過也可以直接在 controller 中直接透過 ORM 撈出該貼文所屬的使用者 id 以及是否為 admin,端看個人造化。

$post = Post::find($id);
$user_id = $post->user_id
  • Step 1 : 建立 Policy

    $ php artisan make:policy PostPolicy
    

    建立後的檔案,路徑與內容如下:
    *app/Policies/PostPolicy.php

    <?php
    
    namespace App\Policies;
    
    use App\User;
    use Illuminate\Auth\Access\HandlesAuthorization;
    
    class PostPolicy
    {
        use HandlesAuthorization;
    
        /**
         * Create a new policy instance.
         *
         * @return void
         */
        public function __construct()
        {
            //
        }
    }
    
    

    若要自動產生CRUD method 的話

    $ php artisan make:policy PostPolicy --model=Post
    

    *app/Policies/PostPolicy.php

    <?php
    
    namespace App\Policies;
    
    use App\Post;
    use App\User;
    use Illuminate\Auth\Access\HandlesAuthorization;
    
    class PostPolicy
    {
        use HandlesAuthorization;
    
        /**
         * Determine whether the user can view any posts.
         *
         * @param  \App\User  $user
         * @return mixed
         */
        public function viewAny(User $user)
        {
            //
        }
    
        /**
         * Determine whether the user can view the post.
         *
         * @param  \App\User  $user
         * @param  \App\Post  $post
         * @return mixed
         */
        public function view(User $user, Post $post)
        {
            //
        }
    
        /**
         * Determine whether the user can create posts.
         *
         * @param  \App\User  $user
         * @return mixed
         */
        public function create(User $user)
        {
            //
        }
    
        /**
         * Determine whether the user can update the post.
         *
         * @param  \App\User  $user
         * @param  \App\Post  $post
         * @return mixed
         */
        public function update(User $user, Post $post)
        {
            //
        }
    
        /**
         * Determine whether the user can delete the post.
         *
         * @param  \App\User  $user
         * @param  \App\Post  $post
         * @return mixed
         */
        public function delete(User $user, Post $post)
        {
            //
        }
    
        /**
         * Determine whether the user can restore the post.
         *
         * @param  \App\User  $user
         * @param  \App\Post  $post
         * @return mixed
         */
        public function restore(User $user, Post $post)
        {
            //
        }
    
        /**
         * Determine whether the user can permanently delete the post.
         *
         * @param  \App\User  $user
         * @param  \App\Post  $post
         * @return mixed
         */
        public function forceDelete(User $user, Post $post)
        {
            //
        }
    }
    
    
  • Step 2 : 註冊 Policy

    *app/Providers/AuthServiceProvider.php

    <?php
    
    namespace App\Providers;
    
    use Illuminate\Support\Facades\Gate;
    use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
    use App\Post;
    use App\Policies\PostPolicy;
    
    class AuthServiceProvider extends ServiceProvider
    {
        /**
         * The policy mappings for the application.
         *
         * @var array
         */
    
        // 在此註冊 Policy
        protected $policies = [
            // 'App\Model' => 'App\Policies\ModelPolicy',
            Post::class => PostPolicy::class,
        ];
    
        /**
         * Register any authentication / authorization services.
         *
         * @return void
         */
        public function boot()
        {
            $this->registerPolicies();
    
            //
        }
    }
    
  • Step 3 : 設計 Policy

    • update

      use Illuminate\Auth\Access\Response;
      
      /*
      ...
      */
      
      public function update(User $user, Post $post)
      {
          return $user->id === $post->user_id || $user->is_admin;
      }
      
    • delete ( 在 Policy 中 destroy 對應的是 delete)

      use Illuminate\Auth\Access\Response;
      
      /*
      ...
      */
      
      public function delete(User $user, Post $post)
      {
          return $user->id === $post->user_id || $user->is_admin;
      }
      
  • Step 4 : 引用 Policy

    *PostsController@update

    public function update(Request $request, $id)
    {
        $rules = [
            'title' => 'string|min:2|max:500',
            'content' => 'string|min:2|max:1500'
        ];
    
        $validator = Validator::make($request->all(), $rules);
        if($validator->fails()){
            return response(['message' => $validator->errors()]);
        }
    
        $auth_user = request()->get('auth_user')->first();
        $post = Post::find($id);
    
    
        if(!is_null($post)){
            // Policy Authorization
            if($auth_user->can('update', $post)){
                $post->update($request->only(['title', 'content']));
                return response(['data' => $post]);
            }else{
                return response(['message' => 'Unauthorized!!']);
            }
        }else{
            return response(['message' => 'Post not found!']);
        }
    }
    

    *PostsController@destroy

    public function destroy($id)
    {
        $auth_user = request()->get('auth_user')->first();
        $post = Post::find($id);
        if(!is_null($post)){
            // Policy Authorization
            if($auth_user->can('delete', $post)){
                $post->delete();
                return response(['message' => 'Post deleted!!']);
            }else{
                return response(['message' => 'Unauthorized!!']);
            }
        }else{
            return response(['message' => 'Post not found!']);
        }
    }
    
    

Postman 測試

以 update 為例

  • ken : 非貼文擁有者,但為 admin

image alt

image alt

  • king : 非貼文擁有者,也非 admin

image alt

image alt

  • kai : 貼文擁有者

image alt

image alt

post 的部份到此結束,接下來就來處理 category。

參考資料:

  1. Policy : https://laravel.com/docs/6.x/authorization#creating-policies

上一篇
Day 25 : 貼文 ( Controller : update & destroy )
下一篇
Day 27 : category ( migration & Model )
系列文
從零開始的Laravel RESTful api30

尚未有邦友留言

立即登入留言