授权与权限 #
一、授权概述 #
1.1 什么是授权 #
授权是确定用户是否有权限执行某个操作的过程。
text
认证 vs 授权
├── 认证(Authentication)
│ └── 你是谁?
└── 授权(Authorization)
└── 你能做什么?
1.2 授权方式 #
text
Laravel授权方式
├── Gates
│ └── 闭包定义权限
├── Policies
│ └── 类定义资源权限
└── 中间件
└── 路由级别权限检查
二、Gates #
2.1 定义Gate #
php
// app/Providers/AuthServiceProvider.php
public function boot()
{
$this->registerPolicies();
// 简单Gate
Gate::define('access-admin', function ($user) {
return $user->is_admin;
});
// 带参数的Gate
Gate::define('update-post', function ($user, $post) {
return $user->id === $post->user_id;
});
// 使用类方法
Gate::define('edit-settings', [SettingsPolicy::class, 'edit']);
}
2.2 检查Gate #
php
// 通过Gate门面
if (Gate::allows('access-admin')) {
// 允许
}
if (Gate::denies('access-admin')) {
// 拒绝
}
// 带参数检查
if (Gate::allows('update-post', $post)) {
// 允许
}
// 检查任意用户权限
if (Gate::forUser($user)->allows('update-post', $post)) {
// 允许
}
2.3 授权异常 #
php
// 授权失败抛出异常
Gate::authorize('update-post', $post);
// 等同于
if (Gate::denies('update-post', $post)) {
abort(403);
}
2.4 Blade模板 #
blade
@can('update-post', $post)
<a href="{{ route('posts.edit', $post) }}">编辑</a>
@endcan
@cannot('update-post', $post)
<p>无权编辑</p>
@endcannot
@canany(['update-post', 'delete-post'], $post)
<p>可以编辑或删除</p>
@endcanany
三、Policies #
3.1 创建Policy #
bash
php artisan make:policy PostPolicy
# 同时生成模型关联
php artisan make:policy PostPolicy --model=Post
3.2 定义Policy #
php
// app/Policies/PostPolicy.php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
public function viewAny(User $user)
{
return true;
}
public function view(User $user, Post $post)
{
return true;
}
public function create(User $user)
{
return true;
}
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
public function delete(User $user, Post $post)
{
return $user->id === $post->user_id;
}
public function restore(User $user, Post $post)
{
return $user->id === $post->user_id;
}
public function forceDelete(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
3.3 注册Policy #
php
// app/Providers/AuthServiceProvider.php
protected $policies = [
Post::class => PostPolicy::class,
];
3.4 使用Policy #
php
// 控制器中
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// 或
if ($request->user()->cannot('update', $post)) {
abort(403);
}
// 更新文章
}
// 不需要传递模型的方法
public function create(Request $request)
{
$this->authorize('create', Post::class);
// 创建文章
}
3.5 资源控制器授权 #
php
class PostController extends Controller
{
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
}
四、中间件授权 #
4.1 can中间件 #
php
// 路由中使用
Route::put('/posts/{post}', [PostController::class, 'update'])
->middleware('can:update,post');
// 控制器构造函数
public function __construct()
{
$this->middleware('can:update,post')->only('update');
}
五、角色和权限 #
5.1 数据库设计 #
php
// 用户表添加角色字段
Schema::table('users', function (Blueprint $table) {
$table->string('role')->default('user');
});
// 或使用多对多关系
Schema::create('roles', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
Schema::create('permissions', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
Schema::create('role_user', function (Blueprint $table) {
$table->foreignId('role_id')->constrained();
$table->foreignId('user_id')->constrained();
});
Schema::create('permission_role', function (Blueprint $table) {
$table->foreignId('permission_id')->constrained();
$table->foreignId('role_id')->constrained();
});
5.2 用户模型 #
php
class User extends Model
{
public function roles()
{
return $this->belongsToMany(Role::class);
}
public function permissions()
{
return $this->belongsToMany(Permission::class);
}
public function hasRole($role)
{
if (is_string($role)) {
return $this->roles->contains('name', $role);
}
return $role->intersect($this->roles)->isNotEmpty();
}
public function hasPermission($permission)
{
if (is_string($permission)) {
return $this->permissions->contains('name', $permission);
}
return $permission->intersect($this->permissions)->isNotEmpty();
}
public function hasPermissionThroughRole($permission)
{
foreach ($permission->roles as $role) {
if ($this->roles->contains($role)) {
return true;
}
}
return false;
}
}
5.3 定义角色Gate #
php
// AuthServiceProvider.php
public function boot()
{
$this->registerPolicies();
Gate::before(function ($user, $ability) {
if ($user->hasRole('admin')) {
return true;
}
});
Gate::define('edit-posts', function ($user) {
return $user->hasPermission('edit-posts');
});
}
六、策略响应 #
6.1 自定义响应 #
php
class PostPolicy
{
public function update(User $user, Post $post)
{
return $user->id === $post->user_id
? Response::allow()
: Response::deny('您无权编辑此文章');
}
}
6.2 捕获响应消息 #
php
public function update(Request $request, Post $post)
{
$response = Gate::inspect('update', $post);
if ($response->allowed()) {
// 允许
} else {
echo $response->message();
}
}
七、策略发现 #
7.1 自动发现 #
Laravel可以自动发现策略:
php
// app/Providers/AuthServiceProvider.php
protected $policies = [
// 手动注册
];
// 自动发现
public function boot()
{
Gate::guessPolicyNamesUsing(function ($modelClass) {
return 'App\\Policies\\' . class_basename($modelClass) . 'Policy';
});
}
八、完整示例 #
8.1 文章授权 #
php
// PostPolicy.php
class PostPolicy
{
public function viewAny(User $user)
{
return true;
}
public function view(User $user, Post $post)
{
return $post->published || $user->id === $post->user_id;
}
public function create(User $user)
{
return $user->hasVerifiedEmail();
}
public function update(User $user, Post $post)
{
return $user->id === $post->user_id || $user->hasRole('editor');
}
public function delete(User $user, Post $post)
{
return $user->id === $post->user_id || $user->hasRole('admin');
}
public function publish(User $user, Post $post)
{
return $user->hasRole('editor') || $user->hasRole('admin');
}
}
8.2 控制器使用 #
php
class PostController extends Controller
{
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
public function index()
{
$posts = Post::all();
return view('posts.index', compact('posts'));
}
public function create()
{
return view('posts.create');
}
public function store(Request $request)
{
$post = Post::create($request->validated());
return redirect()->route('posts.show', $post);
}
public function edit(Post $post)
{
return view('posts.edit', compact('post'));
}
public function update(Request $request, Post $post)
{
$post->update($request->validated());
return redirect()->route('posts.show', $post);
}
public function destroy(Post $post)
{
$post->delete();
return redirect()->route('posts.index');
}
}
8.3 视图使用 #
blade
@foreach($posts as $post)
<div class="post">
<h2>{{ $post->title }}</h2>
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}">编辑</a>
@endcan
@can('delete', $post)
<form action="{{ route('posts.destroy', $post) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit">删除</button>
</form>
@endcan
</div>
@endforeach
九、总结 #
9.1 核心概念 #
| 概念 | 说明 |
|---|---|
| Gate | 闭包定义权限 |
| Policy | 类定义资源权限 |
| authorize() | 授权检查方法 |
| @can | Blade授权指令 |
| can中间件 | 路由授权中间件 |
9.2 下一步 #
掌握了授权系统后,让我们继续学习 RESTful API,了解Laravel API开发!
最后更新:2026-03-28