Laravel Sanctum:SPA 认证与 API Token
Laravel Sanctum 提供两种认证模式:SPA Cookie 认证(适合 Vue/React 前端与 Laravel 同域的应用)和 API Token 认证(适合移动端、第三方客户端)。两种模式可以共存。
安装
# Laravel 11 自带,通过以下命令初始化
php artisan install:api
# 创建 routes/api.php,运行 Sanctum 迁移(personal_access_tokens 表)
# 如果手动安装:
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
模式一:API Token 认证
适合移动端 APP、CLI 工具、第三方服务集成:
// app/Models/User.php
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
// 登录 API:颁发 Token
// app/Http/Controllers/Auth/LoginController.php
class LoginController extends Controller
{
public function __invoke(Request $request)
{
$request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (!Auth::attempt($request->only('email', 'password'))) {
return response()->json(['message' => '邮箱或密码错误'], 401);
}
$user = $request->user();
// 颁发 Token(可以限定能力)
$token = $user->createToken(
name: $request->device_name ?? 'api-token',
abilities: ['tasks:read', 'tasks:write'], // 可选:Token 能力限制
);
return response()->json([
'token' => $token->plainTextToken, // 只返回一次!
'user' => new UserResource($user),
]);
}
}
// 登出 API:撤销当前 Token
class LogoutController extends Controller
{
public function __invoke(Request $request)
{
$request->user()->currentAccessToken()->delete();
return response()->noContent();
}
}
// 撤销所有 Token("退出所有设备")
$user->tokens()->delete();
// routes/api.php
Route::post('/login', LoginController::class);
Route::post('/register', RegisterController::class);
Route::middleware('auth:sanctum')->group(function () {
Route::post('/logout', LogoutController::class);
Route::apiResource('tasks', TaskController::class);
});
# 客户端请求:在 Header 中携带 Token
GET /api/v1/tasks
Authorization: Bearer 1|abc123xyz...
Accept: application/json
Token 能力(Abilities)
// 颁发有限制的 Token
$token = $user->createToken('readonly-token', ['tasks:read']);
// 在控制器中检查能力
public function destroy(Task $task)
{
if (!$request->user()->tokenCan('tasks:delete')) {
return response()->json(['error' => 'Token 无删除权限'], 403);
}
$task->delete();
}
// 在路由中间件中检查(自定义中间件)
// 或使用 Sanctum 内置的 ability 中间件:
Route::delete('/tasks/{task}', [TaskController::class, 'destroy'])
->middleware('ability:tasks:delete');
模式二:SPA Cookie 认证
适合同域的 Vue/React SPA(前后端分离但同域名或通过 CORS 配置):
// config/sanctum.php
// stateful domains:这些域名的请求会使用 Cookie 认证
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,127.0.0.1')),
// .env
SANCTUM_STATEFUL_DOMAINS=taskflow.app,www.taskflow.app
SESSION_DOMAIN=.taskflow.app // 跨子域名共享 Session
// 前端(Vue/React)SPA 流程:
// 步骤1:获取 CSRF Cookie(必须在登录前调用)
await axios.get('/sanctum/csrf-cookie');
// Laravel 设置 XSRF-TOKEN Cookie
// 步骤2:登录(Axios 自动在请求头带 X-XSRF-TOKEN)
await axios.post('/login', { email, password });
// 服务器创建 Session,返回认证 Cookie
// 步骤3:之后所有请求自动携带 Cookie 认证
const { data } = await axios.get('/api/tasks');
// bootstrap/app.php 中确保 Sanctum 中间件在 API 组中:
->withMiddleware(function (Middleware $middleware) {
$middleware->api(prepend: [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
]);
})
注册流程完整示例
// app/Http/Controllers/Auth/RegisterController.php
class RegisterController extends Controller
{
public function __invoke(StoreUserRequest $request)
{
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => bcrypt($request->password),
]);
// 分配默认角色
$user->assignRole('member');
// 发送验证邮件
$user->sendEmailVerificationNotification();
// 立即颁发 Token(或者要求先验证邮件)
$token = $user->createToken('registration-token');
return response()->json([
'message' => '注册成功,请检查邮件验证账号',
'token' => $token->plainTextToken,
'user' => new UserResource($user),
], 201);
}
}
下一节:Gates 与 Policies:细粒度权限控制——Sanctum 处理"你是谁",Gates 和 Policies 处理"你能做什么"。Policy 可以精细到"你只能删除自己的任务"。