API认证 #
一、API认证概述 #
1.1 认证方式 #
text
Laravel API认证方式
├── Sanctum
│ ├── API Token认证
│ └── SPA认证
├── Passport
│ └── OAuth2认证
└── Basic Auth
└── HTTP基础认证
二、Laravel Sanctum #
2.1 安装Sanctum #
bash
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
2.2 配置Sanctum #
php
// config/sanctum.php
return [
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', '')),
'guard' => ['web'],
'expiration' => null,
'middleware' => [
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
],
];
2.3 发布Token #
php
use Laravel\Sanctum\HasApiTokens;
class User extends Model
{
use HasApiTokens;
}
// 控制器中
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('api-token')->plainTextToken;
return response()->json([
'user' => $user,
'token' => $token,
]);
}
2.4 保护路由 #
php
// 路由
Route::middleware('auth:sanctum')->group(function () {
Route::get('/user', function (Request $request) {
return $request->user();
});
Route::apiResource('posts', PostController::class);
});
2.5 Token能力 #
php
// 创建带能力的Token
$token = $user->createToken('api-token', ['post:create', 'post:update'])->plainTextToken;
// 检查能力
if ($user->tokenCan('post:create')) {
// 允许创建
}
// 中间件检查
Route::middleware(['auth:sanctum', 'abilities:post:create'])->group(function () {
// ...
});
2.6 撤销Token #
php
// 撤销当前Token
$request->user()->currentAccessToken()->delete();
// 撤销所有Token
$request->user()->tokens()->delete();
// 撤销指定Token
$request->user()->tokens()->where('id', $tokenId)->delete();
2.7 Token过期 #
php
// config/sanctum.php
'expiration' => 525600, // 1年(分钟)
// 或在创建时设置
$token = $user->createToken('api-token', ['*'], now()->addDays(7));
三、Laravel Passport #
3.1 安装Passport #
bash
composer require laravel/passport
php artisan migrate
php artisan passport:install
3.2 配置Passport #
php
// app/Models/User.php
use Laravel\Passport\HasApiTokens;
class User extends Model
{
use HasApiTokens;
}
// app/Providers/AuthServiceProvider.php
use Laravel\Passport\Passport;
public function boot()
{
Passport::loadKeysFrom(storage_path());
Passport::tokensExpireIn(now()->addDays(15));
Passport::refreshTokensExpireIn(now()->addDays(30));
Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}
// config/auth.php
'guards' => [
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
3.3 授权类型 #
密码授权
php
// 获取Token
$token = $user->createToken('MyApp')->accessToken;
// 或通过HTTP请求
Route::post('/oauth/token', function (Request $request) {
$request->request->add([
'grant_type' => 'password',
'client_id' => config('services.passport.client_id'),
'client_secret' => config('services.passport.client_secret'),
'username' => $request->email,
'password' => $request->password,
'scope' => '',
]);
$tokenRequest = Request::create('/oauth/token', 'POST');
return app()->handle($tokenRequest);
});
客户端凭证授权
php
Route::post('/oauth/token', function (Request $request) {
$request->request->add([
'grant_type' => 'client_credentials',
'client_id' => $request->client_id,
'client_secret' => $request->client_secret,
'scope' => '',
]);
$tokenRequest = Request::create('/oauth/token', 'POST');
return app()->handle($tokenRequest);
});
3.4 保护路由 #
php
Route::middleware('auth:api')->group(function () {
Route::get('/user', function (Request $request) {
return $request->user();
});
});
3.5 Token作用域 #
php
// 定义作用域
Passport::tokensCan([
'user-read' => '读取用户信息',
'user-write' => '写入用户信息',
'post-read' => '读取文章',
'post-write' => '写入文章',
]);
// 默认作用域
Passport::setDefaultScope([
'user-read',
'post-read',
]);
// 检查作用域
if ($user->tokenCan('user-write')) {
// 允许
}
// 中间件
Route::middleware(['auth:api', 'scope:user-read,user-write'])->group(function () {
// ...
});
四、SPA认证 #
4.1 配置 #
env
SANCTUM_STATEFUL_DOMAINS=localhost,127.0.0.1
SESSION_DOMAIN=localhost
4.2 CSRF保护 #
php
// 获取CSRF Token
Route::get('/sanctum/csrf-cookie', function () {
return response()->noContent();
});
4.3 前端请求 #
javascript
// 获取CSRF Cookie
await axios.get('/sanctum/csrf-cookie');
// 登录
await axios.post('/login', {
email: 'user@example.com',
password: 'password',
});
// 获取用户信息
const response = await axios.get('/api/user');
五、移动端认证 #
5.1 发布Token #
php
public function login(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
'device_name' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
return response()->json([
'message' => '认证失败',
], 401);
}
return response()->json([
'token' => $user->createToken($request->device_name)->plainTextToken,
]);
}
5.2 请求认证 #
bash
curl -H "Authorization: Bearer {token}" \
-H "Accept: application/json" \
http://example.com/api/user
六、认证中间件 #
6.1 自定义中间件 #
php
class EnsureTokenIsValid
{
public function handle($request, Closure $next)
{
if (!$request->bearerToken()) {
return response()->json([
'message' => '未提供认证Token',
], 401);
}
return $next($request);
}
}
6.2 注册中间件 #
php
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'token.valid' => \App\Http\Middleware\EnsureTokenIsValid::class,
]);
})
七、最佳实践 #
7.1 Token存储 #
php
// 安全存储Token
// 数据库加密
Schema::table('personal_access_tokens', function (Blueprint $table) {
$table->text('token')->change(); // 加密存储
});
7.2 Token刷新 #
php
// 定期刷新Token
$user->tokens()->where('created_at', '<', now()->subDays(30))->delete();
7.3 限制Token数量 #
php
// 限制用户Token数量
if ($user->tokens()->count() >= 5) {
// 删除最旧的Token
$user->tokens()->oldest()->first()->delete();
}
八、总结 #
8.1 认证方式选择 #
| 场景 | 推荐方案 |
|---|---|
| SPA应用 | Sanctum Cookie认证 |
| 移动应用 | Sanctum Token认证 |
| 第三方应用 | Passport OAuth2 |
| 简单API | Sanctum Token认证 |
8.2 下一步 #
掌握了API认证后,让我们继续学习 中间件,了解Laravel中间件系统!
最后更新:2026-03-28