jwt认证在laravel中需手动替换api guard驱动为jwt,而非简单集成;须配置config/auth.php、显式扩展guard、正确生成并返回token,且登出依赖黑名单机制而非销毁token。

JWT 认证在 Laravel 里不是靠“集成”,而是靠替换默认 guard
Laravel 自带的 token guard(如 api guard)默认用的是数据库 token,不是 JWT。想用 JWT,本质是把 auth:api 中间件背后的认证逻辑换成 JWT 验证流程——不是加个包就自动生效,得动 config/auth.php 和 AuthServiceProvider。
常见错误现象:Auth::user() 返回 null,但请求头带了 Authorization: Bearer xxx;或者 auth()->attempt() 成功却拿不到 token——说明 guard 没切到 JWT 实现,还在走 session 或 DB token 流程。
- 必须把
'api' => ['driver' => 'jwt']写进config/auth.php的guards配置里(前提是已注册jwtdriver) - 推荐用 tymondesigns/jwt-auth(Laravel 8 及以下)或 PHP-Open-Source-Saver/jwt-auth(Laravel 9+),后者是前者维护者重启的官方继任者
- 别在
Auth::attempt()后直接返回用户数据——JWT 场景下,它只负责生成 token,用户信息要靠后续中间件解析 token 得到
如何让 login 接口正确返回 JWT token 而不是重定向或 401
默认的 LoginController 是为 session 登录设计的,直接复用会跳转或报错。JWT 登录必须是纯 API 行为:接收凭证、验证、签发 token、返回 JSON。
使用场景:移动端、前端分离项目、需要跨域认证的接口。
- 删掉
AuthenticatesUserstrait 中的重定向逻辑,自己写login方法 - 验证通过后,用
JWTAuth::fromUser($user)(旧版)或JWTAuth::attempt($credentials)(新版)生成 token - 确保响应是
response()->json(['token' => $token]),而不是redirect()或视图渲染 - 如果遇到
TokenBlacklistException或TokenExpiredException,说明 token 签发后没被正确消费,检查前端是否漏传Authorization头
Laravel 9+ 使用 PHP-Open-Source-Saver/jwt-auth 的关键配置点
新版包不再自动注册 service provider,也不再修改 config/auth.php,所有配置都要手动对齐,否则 guard 找不到 driver。
性能影响:JWT 解析是 CPU 密集型操作,不建议在每次请求都做完整验签(比如静态资源路由也套 auth:api);兼容性上,它默认用 HS256,密钥存在 .env 的 JWT_SECRET,别手误写成 APP_KEY。
- 运行
php artisan vendor:publish --provider="PHPOpenSourceSaver\JWTAuth\Providers\LaravelServiceProvider"生成config/jwt.php - 在
config/auth.php的guards.api.driver改为jwt,并确认providers.users.model指向正确的 User 模型 - 在
App\Providers\AuthServiceProvider@boot()中调用Auth::extend('jwt', function () { ... })——新版包要求显式扩展 guard - 测试时用
curl -H "Authorization: Bearer your_token_here" http://localhost/api/user,别依赖浏览器直接访问,容易忽略 header
为什么 logout 失败或 token 还能用?JWT 黑名单不是银弹
JWT 本身无状态,服务端不存 token,所谓“退出登录”其实是把 token 加入黑名单(blacklist),下次解析时主动拒绝。但黑名单有生命周期,且依赖存储驱动(默认 Redis),配置不对就形同虚设。
容易踩的坑:Auth::logout() 不等于“销毁 token”,它只是清空当前请求的认证状态;前端删了 localStorage 的 token,不代表服务端不能继续认这个 token。
- 确保
JWT_BLACKLIST_ENABLED=true且JWT_BLACKLIST_GRACE_PERIOD=0(否则刚登出立刻重放仍可能成功) - 黑名单存储必须和应用部署环境一致——本地用 file,线上用 Redis,但没配好就会“登出无效”
- 不要依赖黑名单做高安全场景的强退出(如金融类),敏感操作应配合一次性 token 或服务端 session 绑定
-
JWTAuth::invalidate($token)必须传入原始 token 字符串,不是Auth::user()对象
最常被忽略的是:JWT 的“无状态”是相对的——黑名单机制已经悄悄引入了服务端状态。真要零状态,就得接受无法主动作废 token,只能靠缩短 TTL 和前端自律。










