在 Laravel 中使用 Passport 配置 OAuth 2.1 需要结合其安全规范(如强制 PKCE、废除隐式授权等)。以下是完整配置指南:
1. 安装 Laravel Passport
composer require laravel/passport
php artisan passport:install # 生成加密密钥和客户端表
php artisan migrate # 创建 oauth_* 表
2. 基础配置
注册服务提供者
在 app/Providers/AuthServiceProvider.php
中:
use Laravel\Passport\Passport;
public function boot() {
Passport::routes(); // 注册 OAuth2 路由
Passport::hashClientSecrets(); // 加密客户端密钥(OAuth 2.1 推荐)
Passport::enableAuthorizationCodeGrant(); // 仅启用授权码模式
Passport::disableImplicitGrant(); // 禁用隐式授权(OAuth 2.1 废除)
Passport::disablePasswordGrant(); // 禁用密码模式(OAuth 2.1 废除)
}
用户模型配置
在 app/Models/User.php
中:
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable {
use HasApiTokens, Notifiable;
}
Auth 配置
在 config/auth.php
中:
'guards' => [
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
3. 强制 PKCE(OAuth 2.1 核心)
Passport 默认支持 PKCE,但需确保客户端正确使用。
创建 PKCE 客户端
php artisan passport:client --public --redirect_uri="https://your-app/callback"
或通过代码创建:
Passport::client()->forceFill([
'user_id' => null,
'name' => 'PKCE Client',
'secret' => null, // 公共客户端不存储密钥
'redirect' => 'https://your-app/callback',
'personal_access_client' => false,
'password_client' => false,
'revoked' => false,
'public_client' => true, // 标记为公共客户端(如 SPA)
])->save();
前端 PKCE 流程示例(SPA)
- 生成
code_verifier
和code_challenge
:
// 使用 crypto-js 或类似库
const codeVerifier = generateRandomString(128);
const codeChallenge = base64UrlEncode(sha256(codeVerifier));
- 跳转授权页:
GET /oauth/authorize?
response_type=code&
client_id=your-client-id&
redirect_uri=https://your-app/callback&
scope=user-info&
code_challenge=your-code-challenge&
code_challenge_method=S256
- 用
code_verifier
交换令牌:
POST /oauth/token
Content-Type: application/json
{
"grant_type": "authorization_code",
"client_id": "your-client-id",
"redirect_uri": "https://your-app/callback",
"code": "authorization-code-from-callback",
"code_verifier": "your-original-code-verifier"
}
4. 令牌生命周期管理(OAuth 2.1 改进)
短期访问令牌 + 刷新令牌
在 AppServiceProvider
中配置:
Passport::tokensExpireIn(now()->addHours(1)); // 访问令牌 1 小时过期
Passport::refreshTokensExpireIn(now()->addDays(30)); // 刷新令牌 30 天过期
刷新令牌绑定
确保刷新令牌仅能由原客户端使用:
// 在 AuthServiceProvider 中
Passport::refreshTokensBindToClient();
5. 安全增强配置
强制 HTTPS
在 AppServiceProvider
中:
URL::forceScheme('https'); // OAuth 2.1 要求所有通信加密
令牌作用域限制
颁发令牌时限制最小权限:
$token = $user->createToken('token-name', ['read:user']); // 仅允许读取用户信息
撤销令牌
$user->tokens()->where('id', $tokenId)->delete(); // 主动撤销令牌
6. 完整 OAuth 2.1 端点列表
端点 | 路径 | 用途 |
---|---|---|
授权页 | /oauth/authorize | 获取授权码(强制 PKCE) |
令牌颁发 | /oauth/token | 用授权码/刷新令牌交换新令牌 |
令牌撤销 | /oauth/token/revoke | 主动撤销令牌 |
客户端管理 | /oauth/clients | 管理 OAuth 客户端(需认证) |
7. 测试验证
使用 Postman 测试 PKCE 流程
- 设置环境变量:
code_verifier
= 随机字符串code_challenge
=BASE64URL-ENCODE(SHA256(code_verifier))
- 发送授权请求:
GET /oauth/authorize?response_type=code&client_id=1&redirect_uri=https://your-app/callback&code_challenge=...
- 用返回的
code
交换令牌:POST /oauth/token Body: { "code_verifier": "...", "code": "..." }
8. 常见问题
错误:invalid_grant
- 确保
code_verifier
与授权请求的code_challenge
匹配。 - 检查
redirect_uri
完全一致(包括末尾斜杠)。
错误:unsupported_grant_type
- 确认已禁用密码和隐式授权:
Passport::disablePasswordGrant(); Passport::disableImplicitGrant();
总结
通过以上配置,你的 Laravel Passport 将符合 OAuth 2.1 规范:
- 强制 PKCE 防护授权码劫持。
- 废除隐式/密码模式 消除已知风险。
- 短期令牌 + 绑定刷新令牌 增强安全性。
- 强制HTTPS 保障传输安全。