本文目录导读:

Laravel的策略授权(Policy)是用于组织特定模型授权逻辑的类,我来详细讲解如何创建和使用:
创建策略
手动创建
php artisan make:policy PostPolicy
带模型创建(自动生成常用方法)
php artisan make:policy PostPolicy --model=Post
定义策略方法
<?php
namespace App\Policies;
use App\Models\User;
use App\Models\Post;
use Illuminate\Auth\Access\Response;
class PostPolicy
{
/**
* 查看列表
*/
public function viewAny(User $user)
{
return true;
}
/**
* 查看单个文章
*/
public function view(User $user, Post $post)
{
// 公开文章或作者可查看
if ($post->status === 'published') {
return true;
}
return $user->id === $post->user_id;
}
/**
* 创建文章
*/
public function create(User $user)
{
return $user->role === 'author' || $user->role === 'admin';
}
/**
* 更新文章
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id
? Response::allow()
: Response::deny('您不能编辑别人的文章');
}
/**
* 删除文章
*/
public function delete(User $user, Post $post)
{
// 文章作者或管理员可以删除
return $user->id === $post->user_id || $user->isAdmin();
}
/**
* 批量删除
*/
public function deleteAny(User $user)
{
return $user->isAdmin();
}
/**
* 恢复软删除的文章
*/
public function restore(User $user, Post $post)
{
return $user->isAdmin();
}
/**
* 永久删除
*/
public function forceDelete(User $user, Post $post)
{
return $user->isAdmin();
}
}
注册策略
自动发现(推荐)
在 App\Providers\AuthServiceProvider 中:
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use App\Models\Post;
use App\Policies\PostPolicy;
class AuthServiceProvider extends ServiceProvider
{
/**
* 模型与策略的映射
*/
protected $policies = [
Post::class => PostPolicy::class,
// 其他模型...
];
public function boot()
{
$this->registerPolicies();
}
}
自动发现规则
Laravel 会自动发现策略,只要遵循命名规则:
- 模型在
App\Models\Post - 策略在
App\Policies\PostPolicy
使用策略授权
控制器中使用
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* 创建文章
*/
public function store(Request $request)
{
// 检查当前用户是否有创建权限
$this->authorize('create', Post::class);
// 或者使用 Gate facade
// if (!Gate::allows('create', Post::class)) {
// abort(403);
// }
// 创建文章...
}
/**
* 更新文章
*/
public function update(Request $request, Post $post)
{
// 检查当前用户是否有更新该文章的权限
$this->authorize('update', $post);
// 更新文章...
}
/**
* 删除文章
*/
public function destroy(Post $post)
{
// 检查删除权限
$this->authorize('delete', $post);
$post->delete();
return redirect()->route('posts.index');
}
}
在控制器构造函数中自动授权
class PostController extends Controller
{
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
}
在 Blade 模板中使用
{{-- 使用 can 指令 --}}
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}">编辑</a>
@endcan
{{-- 使用 cannot 指令 --}}
@cannot('delete', $post)
<p>您没有删除权限</p>
@endcan
{{-- 在表单中使用 --}}
@can('create', App\Models\Post::class)
<a href="{{ route('posts.create') }}">创建文章</a>
@endcan
{{-- 使用授权结果对象 --}}
@can('update', $post)
<form action="{{ route('posts.update', $post) }}" method="POST">
@csrf
@method('PUT')
<button type="submit">更新</button>
</form>
@elsecan('delete', $post)
<p>只有管理员可以删除</p>
@else
<p>您没有操作权限</p>
@endcan
在路由中使用
Route::middleware('can:update,post')->put('/posts/{post}', [PostController::class, 'update']);
Route::middleware('can:create,App\Models\Post')->post('/posts', [PostController::class, 'store']);
在请求验证中使用
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdatePostRequest extends FormRequest
{
public function authorize()
{
return $this->user()->can('update', $this->post);
}
public function rules()
{
return [
'title' => 'required|string|max:255',
'content' => 'required|string',
];
}
}
使用示例(第一段):## 完整实战示例
### 1. 创建迁移和数据模型
```php
// database/migrations/xxx_create_posts_table.php
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('title');
$table->text('content');
$table->enum('status', ['draft', 'published', 'archived'])->default('draft');
$table->softDeletes();
$table->timestamps();
});
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Post extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = ['title', 'content', 'status', 'user_id'];
public function user()
{
return $this->belongsTo(User::class);
}
}
// app/Models/User.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Database\Eloquent\Relations\HasMany;
class User extends Authenticatable
{
use HasFactory;
protected $fillable = ['name', 'email', 'password', 'role'];
protected $hidden = ['password', 'remember_token'];
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
public function isAdmin(): bool
{
return $this->role === 'admin';
}
public function isEditor(): bool
{
return $this->role === 'editor';
}
}
创建策略类
// app/Policies/PostPolicy.php
namespace App\Policies;
use App\Models\User;
use App\Models\Post;
use Illuminate\Auth\Access\Response;
class PostPolicy
{
/**
* 查看文章列表(所有登录用户可以查看)
*/
public function viewAny(User $user): bool
{
return true;
}
/**
* 查看单个文章(公开文章或作者可查看)
*/
public function view(User $user, Post $post): bool
{
if ($post->status === 'published') {
return true;
}
return $user->id === $post->user_id;
}
/**
* 创建文章(作者和管理员可以创建)
*/
public function create(User $user): bool
{
return true; // 所有登录用户都可以创建
}
/**
* 更新文章(作者本人或管理员)
*/
public function update(User $user, Post $post): Response
{
if ($user->id === $post->user_id) {
return Response::allow('您是这个文章的作者');
}
if ($user->isAdmin()) {
return Response::allow('管理员可以编辑任何文章');
}
return Response::deny('您没有权限编辑其他用户发布的文章');
}
/**
* 删除文章(作者本人或管理员)
*/
public function delete(User $user, Post $post): bool
{
return $user->id === $post->user_id || $user->isAdmin();
}
/**
* 批量删除(仅管理员)
*/
public function deleteAny(User $user): bool
{
return $user->isAdmin();
}
/**
* 恢复被删除的文章(仅管理员)
*/
public function restore(User $user, Post $post): bool
{
return $user->isAdmin();
}
/**
* 永久删除(仅管理员)
*/
public function forceDelete(User $user, Post $post): bool
{
return $user->isAdmin();
}
/**
* 发布文章(作者本人或管理员)
*/
public function publish(User $user, Post $post): bool
{
return $user->id === $post->user_id || $user->isAdmin();
}
/**
* 归档文章(仅管理员)
*/
public function archive(User $user, Post $post): bool
{
return $user->isAdmin();
}
}
注册策略
// app/Providers/AuthServiceProvider.php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use App\Models\Post;
use App\Policies\PostPolicy;
use App\Models\User;
class AuthServiceProvider extends ServiceProvider
{
/**
* 策略映射
*/
protected $policies = [
Post::class => PostPolicy::class,
];
public function boot()
{
$this->registerPolicies();
// 定义额外的 Gate(针对不同场景)
Gate::define('manage-posts', function (User $user) {
return $user->isAdmin() || $user->isEditor();
});
}
}
控制器使用示例
// app/Http/Controllers/PostController.php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class PostController extends Controller
{
/**
* 显示文章列表
*/
public function index()
{
$posts = Post::where('status', 'published')->get();
return view('posts.index', compact('posts'));
}
/**
* 显示创建表单
*/
public function create()
{
$this->authorize('create', Post::class);
return view('posts.create');
}
/**
* 保存新文章
*/
public function store(Request $request)
{
$this->authorize('create', Post::class);
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
]);
$post = Auth::user()->posts()->create($validated);
return redirect()->route('posts.show', $post)->with('success', '文章创建成功!');
}
/**
* 显示单个文章
*/
public function show(Post $post)
{
$this->authorize('view', $post);
return view('posts.show', compact('post'));
}
/**
* 显示编辑表单
*/
public function edit(Post $post)
{
$this->authorize('update', $post);
return view('posts.edit', compact('post'));
}
/**
* 更新文章
*/
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
'status' => 'sometimes|in:draft,published,archived',
]);
$post->update($validated);
return redirect()->route('posts.show', $post)->with('success', '文章更新成功!');
}
/**
* 删除文章
*/
public function destroy(Post $post)
{
$this->authorize('delete', $post);
$post->delete();
return redirect()->route('posts.index')->with('success', '文章已删除!');
}
/**
* 发布文章(自定义操作)
*/
public function publish(Post $post)
{
$this->authorize('publish', $post);
$post->update(['status' => 'published']);
return back()->with('success', '文章已发布!');
}
}
视图中的使用
{{-- resources/views/posts/show.blade.php --}}
@extends('layouts.app')
@section('content')
<div class="container">
<h1>{{ $post->title }}</h1>
<p class="text-muted">
By {{ $post->user->name }} |
Status: {{ $post->status }} |
Created: {{ $post->created_at->diffForHumans() }}
</p>
<div class="mt-4">
{{ $post->content }}
</div>
{{-- 使用 @can 指令判断按钮显示 --}}
<div class="mt-4">
{{-- 编辑按钮(当前用户是作者或管理员) --}}
@can('update', $post)
<a href="{{ route('posts.edit', $post) }}" class="btn btn-primary">编辑</a>
@endcan
{{-- 发布按钮(当前用户是作者或管理员) --}}
@can('publish', $post)
@if($post->status === 'draft')
<form action="{{ route('posts.publish', $post) }}" method="POST" class="d-inline">
@csrf
<button type="submit" class="btn btn-success">发布</button>
</form>
@endif
@endcan
{{-- 删除按钮 --}}
@can('delete', $post)
<form action="{{ route('posts.destroy', $post) }}" method="POST" class="d-inline">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger" onclick="return confirm('确定删除吗?')">删除</button>
</form>
@endcan
</div>
{{-- 错误提示 --}}
@can('update', $post)
{{-- 有权限显示的内容 --}}
@elsecan('publish', $post)
{{-- 有发布权限的内容 --}}
@else
<p class="alert alert-warning">您没有权限编辑这篇文章</p>
@endcan
</div>
@endsection
自定义授权消息和响应
// 在策略方法中使用 Response 类自定义错误消息
public function update(User $user, Post $post): Response
{
if ($user->id === $post->user_id) {
return Response::allow();
}
return Response::denyWithStatus(403, '您不能编辑其他人的文章');
// 或
// return Response::deny('自定义错误消息', 403);
}
// 使用 Gate 检查
if (Gate::allows('update', $post)) {
// 允许
}
if (Gate::denies('update', $post)) {
// 拒绝
}
// 检查当前用户
if ($request->user()->can('update', $post)) {
// 允许
}
if ($request->user()->cannot('update', $post)) {
// 拒绝
}
// 对于管理操作
if ($user->can('update', $post)) {
// 有更新权限
}
// 抛出自定义错误
if (!$user->can('update', $post)) {
throw new AuthorizationException('您没有权限执行此操作');
}
// 使用 middleware
Route::put('/posts/{post}', [PostController::class, 'update'])
->middleware('can:update,post');
通过以上示例,你可以看到 Laravel 策略授权提供了灵活且强大的权限控制能力,根据具体需求,你可以自定义更多的授权方法,用于精细化的权限管理。