iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 22
1

實作了資料的撰寫,也實作了針對資料庫的測試。但是還沒有滿足上次我們說的需求!

還記得的話,上次我們說的,是只有登入用戶才能夠撰寫文章

但是前幾天,我們沒有考慮到的是,編輯文章應該「只有當初的作者才能做到」。

今天,我們就來實作寫入文章的權限吧!

只有登入用戶可以撰寫文章

首先,我們要先用 Laravel 提供的 Auth::user() 函式,來取得用戶登入的身份。

如果使用者沒有登入,那麼就不會有對應的 User 物件,Auth::user() 會回傳 null

只要檢查這個函式的回傳是不是 null,我們就可以知道現在的使用者是不是已經登入囉。

現在,只要使用者沒有登入的話,我們就把他導回到 route('login'),也就是登入頁面裡面

public function create()
{
    if (is_null(Auth::user())) {
        return redirect(route('login'));
    }
    return view('posts.create');
}

現在,在沒有登入的情況下嘗試進入 http://127.0.0.1/posts/create ,應該都會被導回到 http://127.0.0.1/login 囉!

接著,我們來為編輯文章加上限制

只有建立文章用戶可以編輯文章

修改文章資料庫

要限制只有當初撰寫文章的人才可以編輯,那麼每篇文章勢必得要紀錄當初的編輯者是誰。

所以,我們要修改一下資料庫的內容,幫 Post 類別加上 user_id

(還有印象的讀者可以先不看「修改文章資料庫」和「增加一對多關係」這幾段,自己實作看看。

再回來看看做法是不是一樣!)

$ php artisan make:migration add_user_id_to_posts_table
Created Migration: 2019_09_24_133820_add_user_id_to_posts_table

接著,我們改寫 migration 如下

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddUserIdToPostsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->bigInteger('user_id')->after('subject_id')->default(0);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->dropColumn('user_id');
        });
    }
}

再來就是我們熟悉的 php artisan migrate 了,運作之後記得到資料庫檢查看看 posts 是否成功的多了一欄 user_id

再來,就是加上在 PostUser 的關係。

增加一對多關係

我們在 Post 類別裡面加上

/**
 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
 */
public function user()
{
    return $this->belongsTo(User::class);
}

User 類別裡面加上

/**
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function posts()
{
    return $this->hasMany(Post::class);
}

這樣就好囉!

自己動手做的讀者,做法是不是和文章裡面一樣呢?

接著,是要在新增文章時,幫文章加上 user_id

新增文章時加上 user_id

要加上 user_id ,我們可以透過 Auth::id() 這個函式,取得現在的用戶 id

我們改寫一下 PostController 裡面的 store()

    public function store(Request $request)
    {
        $post = new Post;
        $post->content = $request->input('content');
        $post->subject_id = 0;
        $post->user_id = Auth::id();
        $post->save();
        return redirect(route('posts.index'));
    }

好了!各位可以嘗試新增文章看看,如果成功的話,現在新增文章之後,新文章的 user_id 應該會有值了!

接著,就是要撰寫編輯的權限控管了!不過在這之前,我們要先學一個新的東西:Laravel Policy!

什麼是 Laravel Policy

簡單的說,Laravel Policy 就是像我們這次的需求一樣,針對一個 Model 或者資源限制權限的時候,可以使用的機制。

首先,我們利用 artisan 來幫我們建立 PostPolicy

php artisan make:policy PostPolicy --model=Post
Policy created successfully.

我們就可以看到建立好的 app/Policies/PostPolicy 類別了!

進去看看,會看到 Laravel 很貼心的幫我們建立好了許多函式,參數也很聰明地幫我們加上了 Post 物件。

這次我們需要的是 update 相關的權限,我們找到 update() 來修改一下條件

public function update(User $user, Post $post)
{
    return $user->id === $post->user_id;
}

接著,我們記得到 app/Providers/AuthServiceProvider 裡面,註冊剛剛建立好的 PostPolicy

protected $policies = [
    // 'App\Model' => 'App\Policies\ModelPolicy',
    Post::class => PostPolicy::class,
];

做好之後,我們就可以實際使用看看囉!

我們改寫 PostControlleredit() 函式,透過使用 cant() 這個函式

讓用戶如果不具有修改這篇文章的權限,就導回文章列表頁面

public function edit(Post $post)
{
    $user = Auth::user();
    if(is_null($user) || $user->cant('update', $post)){
        return redirect(route('posts.index'));
    }
    return view('posts.edit', ['post' => $post]);
}

好囉!我們連線 http://127.0.0.1/posts/1/edit 看看,如果 id 為 1 的 Post 所帶的 user_id 和現在登入的用戶不對應的話,那麼就會被導回 http://127.0.0.1/posts

到這邊,我們所做的用戶驗證就成功囉!


小小總結一下今天我們學到的東西。

今天我們學到怎麼利用 Laravel 的 Policy,以及 User 類別的許多函式,來實作登入才能編輯文章,以及只有是文章作者才能編輯文章,這幾個權限。

希望各位覺得今天有學到新東西,我們明天見!


上一篇
[Day 21] 和資料庫相關的測試!怎麼測試資料庫的存取
下一篇
[Day 23] 談用戶權限,怎麼能不談測試呢?
系列文
Laravel 6.0 初體驗!怎麼用最新的 laravel 架網站!30

尚未有邦友留言

立即登入留言