本文记录 Laravel API 开发的核心知识点,涵盖认证、数据库关系、中间件、API 资源、分页、表单验证、异常处理等模块。
一、Sanctum 认证系统
1.1 Token 格式理解
Token 格式为 1|abc123...:
1 = personal_access_tokens 表的 ID
abc123... = 明文 token(客户端保存)
- 数据库只存哈希值
hash('sha256', 'abc123...')
1.2 验证流程
1 2 3 4 5 6 7
| 客户端发送:1|abc123... ↓ 框架解析:id=1, plainText=abc123... ↓ 查数据库:SELECT * FROM personal_access_tokens WHERE id=1 ↓ 比对哈希:hash('sha256', 'abc123...') === 数据库的 token?
|
1.3 核心代码
注册:
1 2 3 4 5
| $user = User::create([ 'username' => $validated['username'], 'password' => $validated['password'], // Model 自动哈希 ]); $token = $user->createToken('api')->plainTextToken;
|
登录:
1 2 3 4
| if (!Auth::attempt($credentials)) { return ['message' => '用户名或密码错误']; } $token = $request->user()->createToken('api')->plainTextToken;
|
登出(当前设备):
1
| $request->user()->currentAccessToken()->delete();
|
登出(所有设备):
1
| $request->user()->tokens()->delete();
|
1.4 路由保护
1 2 3
| Route::middleware('auth:sanctum')->group(function () { Route::post('/messages', [MessageController::class, 'store']); });
|
1.5 获取当前用户
1.6 关键点
| 要点 |
说明 |
| 密码哈希 |
Model 的 $casts = ['password' => 'hashed'] 自动处理 |
| Token 返回 |
$token->plainTextToken(不是 $token) |
| 多设备 |
每个设备独立 token,登出只删当前设备 |
| 哈希存储 |
数据库不存明文,防止泄露后被直接使用 |
二、数据库关系
2.1 一对多关系
User Model:
1 2 3 4
| public function messages() { return $this->hasMany(Message::class); }
|
Message Model:
1 2 3 4
| public function user() { return $this->belongsTo(User::class); }
|
2.2 预加载(避免 N+1)
1 2 3 4 5 6 7 8
| $messages = Message::all(); foreach ($messages as $message) { $message->user; }
$messages = Message::with('user')->get();
|
2.3 关联用户
数据库添加字段:
1 2 3
| ALTER TABLE messages ADD COLUMN user_id BIGINT UNSIGNED NULL; ALTER TABLE messages ADD CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;
|
创建时自动关联:
1 2
| $validated['user_id'] = $request->user()->id; $message = Message::create($validated);
|
三、中间件权限控制
3.1 创建中间件
1
| php artisan make:middleware CheckMessageOwner
|
3.2 中间件代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public function handle(Request $request, Closure $next): Response { $id = $request->query('id'); $message = Message::find($id); if (!$message) { return response()->json(['code' => 404, 'msg' => '留言不存在'], 404); } if ($message->user_id !== $request->user()->id) { return response()->json(['code' => 403, 'msg' => '无权删除'], 403); } return $next($request); }
|
3.3 注册中间件别名(Laravel 11)
1 2 3 4 5 6
| ->withMiddleware(function (Middleware $middleware): void { $middleware->alias([ 'check-message-owner' => CheckMessageOwner::class, ]); })
|
3.4 路由应用中间件
1 2
| Route::delete('/messages', [MessageController::class, 'destroy']) ->middleware('check-message-owner');
|
四、API 资源
4.1 创建资源类
1 2
| php artisan make:resource UserResource php artisan make:resource MessageResource
|
4.2 定义返回字段
UserResource:
1 2 3 4 5 6 7 8
| public function toArray(Request $request): array { return [ 'id' => $this->id, 'username' => $this->username, ]; }
|
MessageResource(嵌套资源):
1 2 3 4 5 6 7 8 9 10
| public function toArray(Request $request): array { return [ 'id' => $this->id, 'name' => $this->name, 'content' => $this->content, 'created_at' => $this->created_at, 'user' => new UserResource($this->user), ]; }
|
4.3 使用资源
单个资源:
1
| return new MessageResource($message);
|
资源集合:
1
| return MessageResource::collection($messages);
|
五、分页
5.1 使用 paginate()
1
| $messages = Message::latest()->with('user')->paginate($perPage);
|
5.2 返回分页数据
1 2 3 4 5
| return MessageResource::collection($messages) ->additional([ 'code' => 0, 'msg' => 'ok', ]);
|
5.3 返回结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| { "data": [...], "links": { "first": "...", "last": "...", "prev": null, "next": "..." }, "meta": { "current_page": 1, "last_page": 4, "per_page": 10, "total": 19 }, "code": 0, "msg": "ok" }
|
5.4 URL 参数
1
| GET /api/messages?page=2&per_page=10
|
1
| php artisan make:request StoreMessageRequest
|
6.2 定义验证规则
1 2 3 4 5 6 7 8 9 10 11 12 13
| public function authorize(): bool { return true; }
public function rules(): array { return [ 'name' => 'required|max:20', 'email' => 'nullable|email', 'content' => 'required', ]; }
|
6.3 Controller 使用
1 2 3 4 5 6 7
| public function store(StoreMessageRequest $request) { $validated = $request->validated(); $validated['user_id'] = $request->user()->id; $message = Message::create($validated); }
|
6.4 对比原生 PHP
| 原生 PHP |
Laravel Form Request |
| Controller 里写验证 |
独立 Request 类 |
$request->validate([...]) |
$request->validated() |
| 规则分散 |
集中管理 |
| 不可复用 |
可复用 |
七、异常处理(统一错误格式)
7.1 配置位置
1 2 3 4
| ->withExceptions(function (Exceptions $exceptions): void { })
|
7.2 处理验证异常(422)
1 2 3 4 5 6 7 8 9 10 11
| use Illuminate\Validation\ValidationException;
$exceptions->render(function (ValidationException $e, Request $request) { if ($request->is('api/*')) { return response()->json([ 'code' => 422, 'msg' => $e->getMessage(), 'errors' => $e->errors(), ], 422); } });
|
7.3 处理认证异常(401)
1 2 3 4 5 6 7 8 9 10
| use Illuminate\Auth\AuthenticationException;
$exceptions->render(function (AuthenticationException $e, Request $request) { if ($request->is('api/*')) { return response()->json([ 'code' => 401, 'msg' => '无权限访问', ], 401); } });
|
7.4 统一错误格式
| 错误类型 |
返回格式 |
HTTP 状态码 |
| 验证失败 |
{"code":422,"msg":"...","errors":{...}} |
422 |
| 未登录 |
{"code":401,"msg":"无权限访问"} |
401 |
| 无权限 |
{"code":403,"msg":"无权删除"} |
403 |
| 资源不存在 |
{"code":404,"msg":"留言不存在"} |
404 |
八、常用命令汇总
| 命令 |
用途 |
php artisan make:request XxxRequest |
创建表单验证类 |
php artisan make:middleware XxxMiddleware |
创建中间件 |
php artisan make:resource XxxResource |
创建 API 资源 |
php artisan test |
运行测试 |
php artisan vendor/bin/pint |
修复代码风格 |
php artisan migrate |
执行迁移 |
php artisan migrate:rollback |
回滚迁移 |
php artisan tinker |
REPL 交互环境 |
九、对比原生 PHP
| 功能 |
原生 PHP |
Laravel |
| Token 生成 |
bin2hex(random_bytes(32)) |
$user->createToken('api') |
| Token 验证 |
手写 SQL 查询比对 |
auth:sanctum 中间件 |
| 关系查询 |
手写 JOIN SQL |
with('user') 预加载 |
| 验证规则 |
手写 if 判断 |
Form Request 类 |
| 分页 |
手写 LIMIT + COUNT |
paginate() 自动处理 |
| 错误处理 |
各种格式混用 |
统一 JSON 格式 |
十、项目文件结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| learn-laravel/ ├── app/ │ ├── Http/ │ │ ├── Controllers/ # 业务逻辑 │ │ ├── Middleware/ # 中间件 │ │ ├── Requests/ # 表单验证类 │ │ └── Resources/ # API 资源 │ └── Models/ # Eloquent Model ├── bootstrap/ │ └── app.php # 异常处理配置 ├── routes/ │ └── api.php # API 路由 └── database/ └── migrations/ # 数据库迁移
|
参考资料