passport 是 laravel 的 oauth2 服务端实现,不直接处理登录,而是基于已有用户颁发 token;必须先运行 php artisan migrate 和 passport:install,正确配置 passport::routes(),密码模式 username 必须为邮箱,bearer token 请求头需带空格,过期 token 需手动刷新。

Passport 不是开箱即用的“登录组件”,它是 Laravel 提供的一套 OAuth2 服务端实现,核心用途是让你的 API 能被第三方(或你自己的前端 SPA、移动端)安全地访问——它不直接处理用户注册登录,而是基于已有用户体系颁发 token。
安装与基础配置必须执行 php artisan migrate
很多人卡在第一步:装完 laravel/passport 就以为能用了。实际它依赖数据库表存 client、token、auth code 等数据。不跑迁移,所有 Passport::routes() 调用都会报 500 或找不到模型关系。
- 运行
php artisan passport:install前,确保php artisan migrate已成功执行(包括 Passport 自带的 migration) -
passport:install会生成加密密钥并创建一个 Personal Access Client 和一个 Password Grant Client,这两个 client 的id和secret会输出到终端,务必保存——尤其是 Password Grant Client,后续换取access_token必须用到 - 如果误删了 migration 表或想重装,先手动清空
oauth_clients、oauth_access_tokens等表,再运行passport:install --force
AuthServiceProvider 中的 Passport::routes() 要配对启用
Passport 提供了四类路由:/oauth/authorize(授权端点)、/oauth/token(令牌发放)、/oauth/tokens(管理个人 token)、/oauth/clients(管理 client)。但默认只注册部分,漏配会导致 404。
- 在
app/Providers/AuthServiceProvider.php的boot()方法中,必须显式调用:Passport::routes(function ($router) { $router->forAccessTokens(); $router->forPersonalAccessTokens(); $router->forAuthorizationCodes(); }); - 如果你只做密码模式(如移动端登录),至少保留
$router->forAccessTokens();如果还要支持授权码模式(如第三方网站接入),必须加上forAuthorizationCodes() - Laravel 10+ 默认禁用
forPersonalAccessTokens(),若要用createToken()生成测试 token,得手动开启
密码模式(Password Grant)换 token 时,username 字段必须是邮箱
Passport 内置的 GrantPasswordController 默认把 username 当作 email 查询用户。即使你改了 User 模型的 $username 属性为 phone,这里也不会自动适配。
- 请求示例(必须用
email):POST /oauth/token { "grant_type": "password", "client_id": "2", "client_secret": "xxx", "username": "user@example.com", "password": "123456", "scope": "" } - 若坚持用手机号登录,需重写
attemptLogin()方法,或自定义 Grant 类——不要试图 patch Passport 的 vendor 文件 - 注意:该接口不校验 CSRF,仅限 HTTPS 环境使用;生产环境建议配合 rate limiting(如
throttle:10,1)
前端发请求必须带 Authorization: Bearer {token},且不能漏掉空格
这是最常被忽略的细节:Bearer 后面必须有一个英文空格,再接 token 字符串。少这个空格,Laravel 会返回 401,并在日志里写 Token not provided。
- 正确写法:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6Ij... - 错误写法:
Authorization: BearereyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0a...(无空格) - Vue/Axios 示例:
axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('token'); - 另外,
token过期后不会自动刷新——除非你手动实现 refresh flow(用refresh_token换新access_token),而 Passport 默认只对 Password Grant 返回refresh_token
Passport 的复杂性不在安装,而在理解 OAuth2 流程边界:它不管你是怎么认证用户的,只管“已认证用户”如何安全地对外授权。一旦混淆了「用户登录」和「token 发放」两个阶段,问题就会散落在中间件、路由、前端 header、甚至 HTTPS 配置里。











