搜索

📄 文章 📚 合集
热门搜索
🐘 PHP ⚡ Laravel 🎨 Vue.js ⚛️ React 📦 Yii 📘 JavaScript 🗄️ MySQL 🐳 Docker
返回合集

[板块3:Vue 3 + Element Plus 后台(含认证+核心功能)] - 09 - 开发后端认证 API

代码示例
# 后端认证 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 | ✅ 通过 |

---

🧸 adorable code

专注 PHP、JavaScript、Laravel、Vue.js、React、Yii 全栈开发。记录技术探索过程中的灵感与经验,分享工程实践洞见。

hello@adorablecode.com