# 后端认证 API 开发
## 1. 发布 Sanctum 配置
### 1.1 执行命令
php artisan vendor:publish --tag=sanctum-config
php artisan vendor:publish --tag=sanctum-migrations
php artisan migrate --force
### 1.2 说明
| 命令 | 作用 |
|------|------|
| `vendor:publish --tag=sanctum-config` | 生成 `config/sanctum.php` 配置文件 |
| `vendor:publish --tag=sanctum-migrations` | 发布 Sanctum 迁移文件 |
| `migrate --force` | 执行迁移,生成 `personal_access_tokens` 表 |
### 1.3 注意事项
- Sanctum 包在阶段1已经通过 `composer require laravel/sanctum` 安装
- 阶段4只需要发布配置和迁移文件
- 如果提示表已存在,忽略即可
---
## 2. 配置 Sanctum
### 2.1 文件路径
`config/sanctum.php`
### 2.2 修改 stateful 字段
找到 `stateful` 字段(约第 35 行),修改为:
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),
### 2.3 代码说明
| 代码 | 作用 |
|------|------|
| `stateful` 数组 | 告诉 Sanctum 哪些域名使用状态认证 |
| `Sanctum::currentApplicationUrlWithPort()` | 动态获取 `.env` 中的 `APP_URL` |
| 不写死域名 | 用户安装时自动适配自己的域名 |
### 2.4 设计原因
- 用户安装后 `APP_URL` 自动写入 `.env`,Sanctum 自动读取
- 避免硬编码域名导致其他用户无法使用
---
## 3. 配置 bootstrap/app.php
### 3.1 文件路径
`bootstrap/app.php`
### 3.2 完整代码
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
$middleware->api(prepend: [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
]);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
### 3.3 代码说明
| 代码 | 作用 |
|------|------|
| `api: __DIR__.'/../routes/api.php'` | 注册 API 路由文件 |
| `$middleware->api(prepend: [...])` | 在 API 中间件组最前面添加 Sanctum 中间件 |
| `EnsureFrontendRequestsAreStateful` | 确保前端请求使用状态认证 |
### 3.4 遇到的问题及解决
| 项目 | 内容 |
|------|------|
| **问题** | API 请求返回 404 或 HTML 页面 |
| **原因** | `bootstrap/app.php` 中缺少 `api:` 路由注册 |
| **解决方案** | 添加 `api: __DIR__.'/../routes/api.php'` 行 |
---
## 4. 修改 User 模型
### 4.1 文件路径
`app/Models/User.php`
### 4.2 完整代码
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasFactory, Notifiable, HasApiTokens;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
### 4.3 代码说明
| 代码 | 作用 |
|------|------|
| `use Laravel\Sanctum\HasApiTokens` | 导入 Sanctum 的 Trait |
| `use HasApiTokens` | 提供 `createToken()` 方法 |
### 4.4 遇到的问题及解决
| 项目 | 内容 |
|------|------|
| **问题** | 调用 `$user->createToken()` 时报错 `Call to undefined method createToken()` |
| **原因** | User 模型未使用 `HasApiTokens` Trait |
| **解决方案** | 添加 `use HasApiTokens` |
---
## 5. 创建 AuthController
### 5.1 执行命令
php artisan make:controller Admin/AuthController
### 5.2 文件路径
`app/Http/Controllers/Admin/AuthController.php`
### 5.3 完整代码
```php
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AuthController extends Controller
{
public function login(Request $request)
{
$credentials = $request->validate([
'email' => 'required|email',
'password' => 'required',
]);
if (!Auth::attempt($credentials)) {
return response()->json([
'message' => '邮箱或密码错误'
], 401);
}
$user = Auth::user();
$token = $user->createToken('admin-token')->plainTextToken;
return response()->json([
'token' => $token,
'user' => [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
],
]);
}
public function user(Request $request)
{
return response()->json($request->user());
}
public function logout(Request $request)
{
$request->user()->currentAccessToken()->delete();
return response()->json(['message' => '已退出']);
}
}
```
### 5.4 代码说明
| 方法 | 路由 | 作用 | 认证要求 |
|------|------|------|---------|
| `login` | POST /api/admin/login | 验证邮箱密码,返回 Token | 无 |
| `user` | GET /api/admin/user | 获取当前登录用户信息 | 需要 Token |
| `logout` | POST /api/admin/logout | 删除 Token,退出登录 | 需要 Token |
| 代码 | 作用 |
|------|------|
| `$request->validate()` | 验证请求参数 |
| `Auth::attempt()` | 尝试登录验证 |
| `$user->createToken()` | 生成 API Token |
| `plainTextToken` | 获取明文的 Token 字符串 |
| `currentAccessToken()->delete()` | 删除当前使用的 Token |
---
## 6. 创建 API 路由
### 6.1 文件路径
`routes/api.php`
### 6.2 完整代码
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Admin\AuthController;
// 无需认证的路由
Route::post('/admin/login', [AuthController::class, 'login']);
// 需要认证的路由
Route::middleware('auth:sanctum')->prefix('admin')->group(function () {
Route::get('/user', [AuthController::class, 'user']);
Route::post('/logout', [AuthController::class, 'logout']);
});
### 6.3 代码说明
| 代码 | 作用 |
|------|------|
| `Route::post('/admin/login', ...)` | 注册登录路由,无需认证 |
| `Route::middleware('auth:sanctum')` | 使用 Sanctum 认证中间件 |
| `prefix('admin')` | 所有路由前缀加上 `/admin` |
| `group()` | 将相关路由分组管理 |
### 6.4 说明
- Laravel 12 默认不创建 `api.php`,需要手动创建
- 文件位置:`routes/api.php`
---
## 7. 清除缓存
### 7.1 执行命令
```bash
php artisan optimize:clear
```
### 7.2 说明
清除路由、配置、视图等缓存,确保新配置生效。
---
## 8. 测试 API
### 8.1 执行命令
curl -X POST http://engine-api.test/api/admin/login -H "Content-Type: application/json" -d "{\"email\":\"admin@haozhanzhan.com\",\"password\":\"123456\"}"
### 8.2 预期响应
{
"token": "3|xxxxxxxxxxxxxxxxxxxxx",
"user": {
"id": 3,
"name": "管理员",
"email": "admin@haozhanzhan.com"
}
}
### 8.3 测试错误密码
curl -X POST http://engine-api.test/api/admin/login -H "Content-Type: application/json" -d "{\"email\":\"admin@haozhanzhan.com\",\"password\":\"wrong\"}"
预期响应:
```json
{
"message": "邮箱或密码错误"
}
```
---
## 9. 遇到的问题及解决汇总
| 问题 | 原因 | 解决方案 |
|------|------|---------|
| `Table 'personal_access_tokens' already exists` | 迁移已执行过 | 忽略,不影响 |
| `Call to undefined method createToken()` | User 模型缺少 HasApiTokens | 添加 `use HasApiTokens` |
| API 返回 HTML 页面 | `bootstrap/app.php` 缺少 `api:` 路由 | 添加 `api: __DIR__.'/../routes/api.php'` |
| curl 命令换行报错 | Windows CMD 不支持 `\` 换行 | 使用单行命令 |
---
## 10. 验证结果
| 验证项 | 预期结果 | 实际结果 |
|--------|---------|---------|
| 配置文件发布 | `config/sanctum.php` 存在 | ✅ 通过 |
| 迁移执行 | 表创建成功 | ✅ 通过 |
| User 模型 | 包含 HasApiTokens | ✅ 通过 |
| bootstrap/app.php | 包含 api 路由 | ✅ 通过 |
| API 路由 | 返回 JSON | ✅ 通过 |
| 正确账号密码 | 返回 token 和 user | ✅ 通过 |
| 错误密码 | 返回 401 | ✅ 通过 |
---