”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 授权:了解 Laravel 中的策略

授权:了解 Laravel 中的策略

发布于2024-11-04
浏览:258

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]删除
最新教程 更多>
  • 如何在 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
  • 如何使用 MySQL 查找今天生日的用户?
    如何使用 MySQL 查找今天生日的用户?
    如何使用 MySQL 识别今天生日的用户使用 MySQL 确定今天是否是用户的生日涉及查找生日匹配的所有行今天的日期。这可以通过一个简单的 MySQL 查询来实现,该查询将存储为 UNIX 时间戳的生日与今天的日期进行比较。以下 SQL 查询将获取今天有生日的所有用户: FROM USERS ...
    编程 发布于2024-11-17
  • 如何向 Pandas DataFrame 中的字符串添加前导零?
    如何向 Pandas DataFrame 中的字符串添加前导零?
    向 Pandas Dataframe 中的字符串添加前导零在 Pandas 中,处理字符串有时需要修改其格式。一项常见任务是向数据帧中的字符串添加前导零。这在处理需要转换为字符串格式的数值数据(例如 ID 或日期)时特别有用。要实现此目的,您可以利用 Pandas Series 的 str 属性。此...
    编程 发布于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
  • 您是否应该异步加载脚本以提高站点性能?
    您是否应该异步加载脚本以提高站点性能?
    异步脚本加载以提高网站性能在当今的 Web 开发领域,优化页面加载速度对于用户体验和搜索引擎优化至关重要。提高性能的一种有效技术是异步加载脚本,使浏览器能够与其他页面元素并行下载脚本。传统方法是将脚本标签直接放置在 HTML 文档中,但这种方法常常会造成瓶颈因为浏览器必须等待每个脚本完成加载才能继续...
    编程 发布于2024-11-17
  • 如何将 Python 日期时间对象转换为自纪元以来的毫秒数?
    如何将 Python 日期时间对象转换为自纪元以来的毫秒数?
    在 Python 中将日期时间对象转换为自纪元以来的毫秒数Python 的 datetime 对象提供了一种稳健的方式来表示日期和时间。但是,某些情况可能需要将 datetime 对象转换为自 UNIX 纪元以来的毫秒数,表示自 1970 年 1 月 1 日协调世界时 (UTC) 午夜以来经过的毫秒...
    编程 发布于2024-11-17
  • 如何在 Python 中使用特定前缀重命名目录中的多个文件
    如何在 Python 中使用特定前缀重命名目录中的多个文件
    使用Python重命名目录中的多个文件当面临重命名目录中文件的任务时,Python提供了一个方便的解决方案。然而,处理错综复杂的文件重命名可能具有挑战性,特别是在处理特定模式匹配时。为了解决这个问题,让我们考虑一个场景,我们需要从文件名中删除前缀“CHEESE_”,例如“CHEESE_CHEESE_...
    编程 发布于2024-11-17
  • 大批
    大批
    方法是可以在对象上调用的 fns 数组是对象,因此它们在 JS 中也有方法。 slice(begin):将数组的一部分提取到新数组中,而不改变原始数组。 let arr = ['a','b','c','d','e']; // Usecase: Extract till index p...
    编程 发布于2024-11-17
  • Java中的同步静态方法如何处理线程同步?
    Java中的同步静态方法如何处理线程同步?
    Java 中的同步静态方法:解锁对象类困境Java 文档指出,在同一对象上多次调用同步方法不会交错。但是,当涉及静态方法时会发生什么?静态方法不与具体对象关联,那么synchronized关键字是指对象还是类呢?分解答案根据Java语言规范(8.4.3.6),同步方法在执行之前获取监视器。对于静态方...
    编程 发布于2024-11-16
  • 如何修复 macOS 上 Django 中的“配置不正确:加载 MySQLdb 模块时出错”?
    如何修复 macOS 上 Django 中的“配置不正确:加载 MySQLdb 模块时出错”?
    MySQL配置不正确:相对路径的问题在Django中运行python manage.py runserver时,可能会遇到以下错误:ImproperlyConfigured: Error loading MySQLdb module: dlopen(/Library/Python/2.7/site-...
    编程 发布于2024-11-16
  • 如何使用 Python 获取目录中按创建日期排序的文件列表?
    如何使用 Python 获取目录中按创建日期排序的文件列表?
    使用 Python 获取按创建日期排序的目录列表导航目录时,经常需要获取排序后的内容列表根据特定标准,例如创建日期。在Python中,这个任务可以轻松完成。建议方法:为了实现这一点,Python内置的文件系统操作模块和排序功能的组合是受雇。下面的代码片段说明了这个过程:import glob imp...
    编程 发布于2024-11-16
  • 如何在初始页面加载后动态加载 Less.js 规则?
    如何在初始页面加载后动态加载 Less.js 规则?
    动态加载Less.js规则将Less.js合并到网站中可以增强其样式功能。然而,遇到的一个限制是需要在 Less.js 脚本之前加载所有 LESS 样式表。当某些样式需要在初始页面加载后动态加载时,这可能会带来挑战。当前限制目前,Less.js 规定加载外部的顺序样式表和脚本起着至关重要的作用。颠倒...
    编程 发布于2024-11-16
  • 如何在 PHP 中清除浏览器缓存?
    如何在 PHP 中清除浏览器缓存?
    在 PHP 中清除浏览器缓存您可能会遇到需要清除浏览器缓存以强制浏览器重新加载最新版本的情况您的网页。当您开发 Web 应用程序并且希望确保用户看到您所做的最新更改时,这尤其有用。清除浏览器缓存的 PHP 代码要使用PHP清除浏览器缓存,可以使用以下代码:header("Cache-Con...
    编程 发布于2024-11-16

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3