」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 授權:了解 Laravel 中的策略

授權:了解 Laravel 中的策略

發佈於2024-11-04
瀏覽:400

Controlling what users can or cannot do in your application is one of the most essential things you'll need to do when building real-world applications.

For example, in a todo application, you don't want a user to be able to edit or delete other users' todos.

In this article, you will learn one of the seamless ways to do this in Laravel by using policies to control what users can do by building a simple todo application.

To follow along with this tutorial, you need to have a basic understanding of Laravel and its application structure.

Create a Base Application

Run the following command to create a new Laravel application in your desired folder and move into it:

composer create-project laravel/laravel todo-app && cd todo-app

Next, run the following command to install Laravel Breeze:

php artisan breeze:install

Breeze will scaffold your new application with authentication so your users can register, log in, log out, and view their personalized dashboards.

After that, compile your application assets by running the following commands:

npm install && npm run dev

Laravel comes with the file-based SQLite database by default, so the next thing you need to do is connect your application database file to a database viewer like TablePlus or any other one you like.

After connecting your database to the viewer, run the following commands to migrate the available tables into your database:

php artisan migrate

Once that is done, run the following command to view your application in the browser:

php artisan serve

You should now see your new Laravel application at localhost:8000 looking like this:

Authorization: Understanding Policies in Laravel

You can now go to the register page to create a user and access the dashboard, which is the entire application at this point.

Model Setup

Models in Laravel are used to control database tables. Use the following command to create a Todo model in the App/Models folder:

php artisan make:model Todo

Next, inside the newly created file, replace the Todo class with the following code:

class Todo extends Model
{
    use HasFactory;

    protected $fillable = [
        'title',
        'description',
        'completed',
        'user_id'
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

The code above will enable users to submit a form with the $fillable properties; it also defines the relationship between a user and a Todo; in this case, a todo belongs to a user. Let's complete the relationship setup by adding the following code to the App/Models/User.php file:

    public function todos()
    {
        return $this->hasMany(Todo::class);
    }

The code above will connect the User model to the Todo model so that it can have many to-dos.

Migration Setup

Migrations in Laravel are used to specify what should be in a database table. Run the following command to create a migration inside the database/migrations folder:

php artisan make:migration create_todos_table

Next, replace the up function in the new file with the following that will add the todo table to the database with the id, user_id, title, description, completed, and timestamp columns:

   public function up(): void
    {
        Schema::create('todos', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->onDelete('cascade');
            $table->string('title');
            $table->text('description')->nullable();
            $table->boolean('completed')->default(false);
            $table->timestamps();
        });
    }

Next, run the following command to add the todos table to the database:

php artisan migrate

Policy Setup

Policies in Laravel allow you to define who can do what with a particular resource, in this case, todos.

Let's see how that works by generating a TodoPolicy inside the App/Policies folder using the following command:

php artisan make:policy TodoPolicy --model=Todo

Next, in the newly created TodoPolicy file, replace the TodoPolicy class with the following code:

class TodoPolicy
{
    /**
     * Determine if the user can view any todos.
     */
    public function viewAny(User $user): bool
    {
        return true;
    }

    /**
     * Determine if the user can view the todo.
     */
    public function view(User $user, Todo $todo): bool
    {
        return $user->id === $todo->user_id;
    }

    /**
     * Determine if the user can create todos.
     */
    public function create(User $user): bool
    {
        return true;
    }

    /**
     * Determine if the user can update the todo.
     */
    public function update(User $user, Todo $todo): bool
    {
        return $user->id === $todo->user_id;
    }

    /**
     * Determine if the user can delete the todo.
     */
    public function delete(User $user, Todo $todo): bool
    {
        return $user->id === $todo->user_id;
    }
}

The code above specifies that a user can create a todo, but can only view, update, or delete a todo that belongs to them.

Next, let's set up the controller in the next section.

Controller Setup

Controllers in Laravel control the app's functionality for a particular resource. Run the following command to generate a TodoController inside the App/Http/Controllers:

php artisan make:controller TodoController

Add the following code to the top of the newly created TodoController file to import the Todo model for database operations and Gate class for authorization:

use App\Models\Todo;
use Illuminate\Support\Facades\Gate;

Index Method

Replace the index method with the following code that fetches and returns all the logged-in users' todos:

    public function index()
    {
        Gate::authorize('viewAny', Todo::class);
        $todos = auth()->user()->todos;
        return view('todos.index', compact('todos'));
    }

The Gate::authorize method verifies that the user is logged in using the viewAny policy method you defined in the previous section.

Create Method

Replace the create method with the following code that verifies the user is signed in before returning the create todo form to the user so they can create todos:

    public function create()
    {
        Gate::authorize('create', Todo::class);
        return view('todos.create');
    }

Store Method

Replace the store method with the following code that checks if the user can create a todo, validates the request, creates the todo, and redirects the user to the todo list page:

public function store(Request $request)
    {
        Gate::authorize('create', Todo::class);

        $validated = $request->validate([
            'title' => 'required|max:255',
            'description' => 'nullable'
        ]);

        $todo = auth()->user()->todos()->create($validated);

        return redirect()->route('todos.index')
            ->with('success', 'Todo created successfully');
    }

Edit Method

Replace the edit method with the following code that verifies the user can edit that todo before returning the edit todo form populated with the selected todo to the user so they can edit it:

    public function edit(Todo $todo)
    {
        Gate::authorize('update', $todo);
        return view('todos.edit', compact('todo'));
    }

Update Method

Replace the update method with the following code that checks if the user can update the todo, validates the request, updates the selected todo, and redirects the user to the todo list page:

    public function update(Request $request, Todo $todo)
    {
        Gate::authorize('update', $todo);

        $validated = $request->validate([
            'title' => 'required|max:255',
            'description' => 'nullable'
        ]);

        $todo->update($validated);

        return redirect()->route('todos.index')
            ->with('success', 'Todo updated successfully');
    }

Destroy Method

Replace the destroy method with the following code that checks if the user can delete the todo, deletes it, and redirects the user to the todo list page:

    public function destroy(Todo $todo)
    {
        Gate::authorize('delete', $todo);

        $todo->delete();

        return redirect()->route('todos.index')
            ->with('success', 'Todo deleted successfully');
    }

Your TodoController file should now look like this:

user()->todos;
        return view('todos.index', compact('todos'));
    }

    public function create()
    {
        Gate::authorize('create', Todo::class);
        return view('todos.create');
    }

    public function store(Request $request)
    {
        Gate::authorize('create', Todo::class);

        $validated = $request->validate([
            'title' => 'required|max:255',
            'description' => 'nullable'
        ]);

        $todo = auth()->user()->todos()->create($validated);

        return redirect()->route('todos.index')
            ->with('success', 'Todo created successfully');
    }

    public function edit(Todo $todo)
    {
        Gate::authorize('update', $todo);
        return view('todos.edit', compact('todo'));
    }

    public function update(Request $request, Todo $todo)
    {
        Gate::authorize('update', $todo);

        $validated = $request->validate([
            'title' => 'required|max:255',
            'description' => 'nullable'
        ]);

        $todo->update($validated);

        return redirect()->route('todos.index')
            ->with('success', 'Todo updated successfully');
    }

    public function destroy(Todo $todo)
    {
        Gate::authorize('delete', $todo);

        $todo->delete();

        return redirect()->route('todos.index')
            ->with('success', 'Todo deleted successfully');
    }
}

Views Setup

Now that your TodoController methods are all set, you can now create the views for your applications by creating a new todos folder inside the resources/views folder. After that, create create.blade.php, edit.blade.php, index.blade.php files in the new todos folder.

Index View

Paste the following code inside the index.blade.php:

{{ __('Todos') }}

{{-- --}}
@foreach($todos as $todo)

{{ $todo->title }}

{{ $todo->description }}

Edit
@csrf @method('DELETE')
@endforeach

Create View

Paste the following code inside the create.blade.php:

{{ __('Create Todo') }}

@csrf

Edit View

Paste the following code inside the edit.blade.php:

{{ __('Edit Todo') }}

@csrf @method('PUT')

Routes Setup

Handling routes for your TodoController is relatively straightforward using the resource method in Laravel. Do that by adding the following code to the end of the routes/web.php folder like so:

// rest of the file
Route::middleware(['auth'])->group(function () {
    Route::resource('todos', TodoController::class);
});

The code above uses the auth middleware to protect the todos resource. You should now be able to visit the following routes in your application after being logged in:

  • /todos: List all users' todos
  • /todos/create: Shows the form for creating todos
  • /todos/edit/1: Shows the form for editing a todo with the given id; 1 in this case.

You can now create, edit, and delete todos, BUT only as a logged-in user and the owner of the selected todos in the case of editing and deleting.

Conclusion

And that's it! You have just created a realistic todo application that allows users to create, view, edit, and delete ONLY their own todos. Please let me know if you have any corrections, suggestions, or questions in the comments!

Finally, remember to follow me here on Dev, LinkedIn, and Twitter. Thank you so much for reading, and I'll see you in the next one!

版本聲明 本文轉載於:https://dev.to/olodocoder/authorization-understanding-policies-in-laravel-4gao?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 在 Go 中使用 WebSocket 進行即時通信
    在 Go 中使用 WebSocket 進行即時通信
    构建需要实时更新的应用程序(例如聊天应用程序、实时通知或协作工具)需要一种比传统 HTTP 更快、更具交互性的通信方法。这就是 WebSockets 发挥作用的地方!今天,我们将探讨如何在 Go 中使用 WebSocket,以便您可以向应用程序添加实时功能。 在这篇文章中,我们将介绍: WebSoc...
    程式設計 發佈於2024-11-17
  • Bootstrap 4 Beta 中的列偏移發生了什麼事?
    Bootstrap 4 Beta 中的列偏移發生了什麼事?
    Bootstrap 4 Beta:列偏移的刪除和恢復Bootstrap 4 在其Beta 1 版本中引入了重大更改柱子偏移了。然而,隨著 Beta 2 的後續發布,這些變化已經逆轉。 從 offset-md-* 到 ml-auto在 Bootstrap 4 Beta 1 中, offset-md-*...
    程式設計 發佈於2024-11-17
  • Numpy 備忘單
    Numpy 備忘單
    Comprehensive Guide to NumPy: The Ultimate Cheat Sheet NumPy (Numerical Python) is a fundamental library for scientific computing in Python. ...
    程式設計 發佈於2024-11-17
  • 你需要像專業人士一樣閱讀科技文章
    你需要像專業人士一樣閱讀科技文章
    在快节奏的技术世界中,并非您阅读的所有内容都是准确或公正的。并非您读到的所有内容都是由人类编写的! 细节可能存在微妙的错误,或者文章可能故意误导。让我们来看看一些可以帮助您阅读科技文章或任何媒体内容的技能。 1. 培养健康的怀疑态度 培养健康的怀疑态度至关重要。质疑大胆的主张,寻找...
    程式設計 發佈於2024-11-17
  • 大批
    大批
    方法是可以在物件上呼叫的 fns 數組是對象,因此它們在 JS 中也有方法。 slice(begin):將陣列的一部分提取到新數組中,而不改變原始數組。 let arr = ['a','b','c','d','e']; // Usecase: Extract till index ...
    程式設計 發佈於2024-11-17
  • 如何找到一個多維數組中存在但另一個多維數組中不存在的行?
    如何找到一個多維數組中存在但另一個多維數組中不存在的行?
    比較多維數組的關聯行您有兩個多維數組,$pageids 和$parentpage,其中每行代表一個包含列的記錄“id”、“連結標籤”和“url”。您想要尋找 $pageids 中存在但不在 $parentpage 中的行,從而有效地建立一個包含缺少行的陣列 ($pageWithNoChildren)...
    程式設計 發佈於2024-11-17
  • 為什麼 Windows 中會出現「Java 無法辨識」錯誤以及如何修復它?
    為什麼 Windows 中會出現「Java 無法辨識」錯誤以及如何修復它?
    解決Windows 中的「Java 無法識別」錯誤嘗試在Windows 7 上檢查Java 版本時,使用者可能會遇到錯誤「'Java' 無法識別”作為內部或外部命令。 」此問題通常是由於缺少Java 安裝或環境變數不正確而引起的。要解決此問題,您需要驗證Java 安裝並配置必要的環境...
    程式設計 發佈於2024-11-17
  • 儘管檔案存在且有權限,為什麼 File.delete() 會回傳 False?
    儘管檔案存在且有權限,為什麼 File.delete() 會回傳 False?
    儘管存在並進行權限檢查,File.delete() 返回False使用FileOutputStream 寫入檔案後嘗試刪除檔案時,某些使用者遇到意外問題: file.delete() 傳回false。儘管檔案存在且所有權限檢查(.exists()、.canRead()、.canWrite()、.ca...
    程式設計 發佈於2024-11-17
  • 如何有效地從 Go 中的切片中刪除重複的對等點?
    如何有效地從 Go 中的切片中刪除重複的對等點?
    從切片中刪除重複項給定一個文字文件,其中包含表示為具有“Address”和“PeerID”的對象的對等點清單屬性,任務是根據程式碼配置中「Bootstrap」切片中匹配的「Address」和「PeerID」刪除所有重複的對等點。 為了實現此目的,我們迭代切片中的每個對等點物件多次。在每次迭代期間,我...
    程式設計 發佈於2024-11-17
  • 如何在 PHP 中組合兩個關聯數組,同時保留唯一 ID 並處理重複名稱?
    如何在 PHP 中組合兩個關聯數組,同時保留唯一 ID 並處理重複名稱?
    在 PHP 中組合關聯數組在 PHP 中,將兩個關聯數組組合成一個數組是常見任務。考慮以下請求:問題描述:提供的代碼定義了兩個關聯數組,$array1和$array2。目標是建立一個新陣列 $array3,它合併兩個陣列中的所有鍵值對。 此外,提供的陣列具有唯一的 ID,而名稱可能重疊。要求是建構一...
    程式設計 發佈於2024-11-17
  • 如何自訂Bootstrap 4的檔案輸入元件?
    如何自訂Bootstrap 4的檔案輸入元件?
    繞過 Bootstrap 4 檔案輸入的限制Bootstrap 4 提供了自訂檔案輸入元件來簡化使用者的檔案選擇。但是,如果您希望自訂「選擇檔案...」佔位符文字或顯示所選檔案的名稱,您可能會遇到一些挑戰。 更改 Bootstrap 4.1 及更高版本中的佔位符自 Bootstrap 4.1 起,佔...
    程式設計 發佈於2024-11-17
  • 如何在 CSS 盒子上創建斜角?
    如何在 CSS 盒子上創建斜角?
    在 CSS 框上建立斜角可以使用多種方法在 CSS 框上實現斜角。一種方法描述如下:使用邊框的方法此技術依賴於沿容器左側建立透明邊框和沿底部建立傾斜邊框。以下程式碼示範如何實現:<div class="cornered"></div> <div cl...
    程式設計 發佈於2024-11-17
  • 如何在 Pandas DataFrame 中的字串中新增前導零?
    如何在 Pandas DataFrame 中的字串中新增前導零?
    在 Pandas Dataframe 中的字串中加入前導零在 Pandas 中,處理字串有時需要修改其格式。一項常見任務是向資料幀中的字串新增前導零。這在處理需要轉換為字串格式的數值資料(例如 ID 或日期)時特別有用。 要實現此目的,您可以利用 Pandas Series 的 str 屬性。此屬性...
    程式設計 發佈於2024-11-17
  • 您是否應該異步加載腳本以提高網站效能?
    您是否應該異步加載腳本以提高網站效能?
    非同步腳本載入以提高網站效能在現今的Web 開發領域,優化頁面載入速度對於使用者體驗和搜尋引擎優化至關重要。提高效能的有效技術之一是非同步載入腳本,使瀏覽器能夠與其他頁面元素並行下載腳本。 傳統方法是將腳本標籤直接放置在 HTML 文件中,但這種方法常常會造成瓶頸因為瀏覽器必須等待每個腳本完成載入才...
    程式設計 發佈於2024-11-17
  • 如何將 Python 日期時間物件轉換為自紀元以來的毫秒數?
    如何將 Python 日期時間物件轉換為自紀元以來的毫秒數?
    在Python 中將日期時間物件轉換為自紀元以來的毫秒數Python 的datetime 物件提供了一種穩健的方式來表示日期和時間。但是,某些情況可能需要將 datetime 物件轉換為自 UNIX 紀元以來的毫秒數,表示自 1970 年 1 月 1 日協調世界時 (UTC) 午夜以來經過的毫秒數。...
    程式設計 發佈於2024-11-17

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3