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