必须用 Passport:需支持第三方 OAuth 2.0 授权;选 Sanctum:仅自研前端调用 API,更轻量安全。Passport 实现完整 OAuth 流程,Sanctum 是带 Token 管理的 Session 替代方案。

用 Passport 还是 Sanctum?先看你的使用场景
如果你要支持第三方应用(比如独立小程序、合作平台)用 OAuth 2.0 协议来“代表用户”访问你的 API,那就必须用 laravel/passport;如果只是自己写的 Vue/React 前端或 App 调自己的 API,用 laravel/sanctum 更轻、更安全、也更少出错。
Passport 是完整实现 RFC 6749 的 OAuth 2.0 服务器,自带授权码、密码、客户端凭证等 grant 类型;Sanctum 则不走标准 OAuth 流程,它本质是带 Token 管理的 Session 替代方案——没有 access_token/refresh_token 交换,也没有 scope 权限粒度控制。
- 需要
client_id+redirect_uri+ 用户授权跳转 → 必选 Passport - 前端只需登录后拿个 token 放 header 里调 API → Sanctum 足够,且避免了 Passport 的密钥、路由、中间件三重配置负担
- 想让第三方开发者写文档、调试 OAuth 流程 → Passport 提供标准
/oauth/authorize、/oauth/token接口,兼容 Postman 和 OAuth 客户端库
Passport 安装后必做的三件事,缺一不可
很多人跑完 php artisan passport:install 就以为好了,结果请求 /oauth/token 直接 500 或 404——其实是漏掉了关键环节。
- 在
config/auth.php的guards.api.driver必须设为'driver' => 'passport',否则auth:api中间件压根不走 Passport 验证逻辑 -
AuthServiceProvider::boot()里必须调Passport::routes(),否则那些 OAuth 路由根本没注册,artisan route:list里都找不到oauth/authorize -
User模型必须 useLaravel\Passport\HasApiTokenstrait,否则$user->createToken()会报方法不存在
常见错误现象:Class 'Laravel\Passport\HasApiTokens' not found → 没加 trait 或没 autoload;Target class [Laravel\Passport\Http\Controllers\AuthorizationController] does not exist → routes 没注册;invalid_client → client_id 传错或数据库里 client 记录被删过
OAuth 登录时怎么把第三方用户和本地账号关联上?
这不是 Passport 自动处理的,你得自己写逻辑。核心是:拿到第三方返回的唯一标识(如 GitHub 的 id、微信的 unionid),查 authentications 表有没有匹配记录,没有就新建用户并绑定。
典型结构是两张表:
-
users:存本地用户基础信息(id, email, name...) -
authentications:字段含user_id、provider(如'github')、provider_uid(如'123456')
示例伪代码:
if ($auth = Authentication::where('provider', $provider)->where('provider_uid', $userProfile->identifier)->first()) {
$user = $auth->user;
} else {
$user = User::firstOrCreate(['email' => $userProfile->email], [
'name' => $userProfile->displayName,
]);
Authentication::create([
'user_id' => $user->id,
'provider' => $provider,
'provider_uid' => $userProfile->identifier,
]);
}
容易踩的坑:provider_uid 没加数据库索引 → 并发登录时可能重复创建用户;没校验 $userProfile->email 是否已存在 → 同一个邮箱被不同平台反复注册
令牌有效期和刷新机制不是默认就可靠的
Passport 默认 access_token 永不过期,这在生产环境极其危险。必须显式设置:
-
Passport::tokensExpireIn(now()->addMinutes(30))—— 短期 token,适合 Web 前端 -
Passport::refreshTokensExpireIn(now()->addDays(7))—— 刷新 token 有效期要短于 access_token,否则失去刷新意义 - 别忘了在
.env里配好PASSPORT_PERSONAL_ACCESS_CLIENT_ID和_SECRET,否则个人令牌生成失败
性能影响:每次验证 token 都会查 oauth_access_tokens 表,高并发下建议给 id 和 user_id 加索引;若用 Redis 存储 token(需改源码或换包),可降低 DB 压力,但牺牲了 revoke 的原子性
最常被忽略的一点:Passport::tokensExpireIn() 只影响新颁发的 token,已发出的旧 token 不会自动失效——要强制下线,得手动调 $user->tokens()->delete() 或用 oauth_access_tokens 表的 revoked 字段标记


















