JWT认证在Laravel中需手动集成tymon/jwt-auth 2.x(社区维护版),配置服务提供者、发布配置、实现JWTSubject接口;登录需校验字段匹配,刷新依赖黑名单与有效期设置;Header格式(Bearer后空格)和Apache重写规则易致验证失败。

JWT 认证在 Laravel 中不是开箱即用的,必须通过 laravel/jwt-auth(已停止维护)或更现代的替代方案(如 tymon/jwt-auth 的社区维护分支 php-jwt/jwt-auth)实现;当前推荐直接使用 laravel/sanctum 或 laravel/passport,但若项目已依赖 tymon/jwt-auth 且需继续维护,以下操作基于其 2.x 版本(适配 Laravel 9/10)。
安装 tymon/jwt-auth 并配置服务提供者
该包官方主仓库已归档,需使用活跃的 fork 版本。Laravel 9+ 不再自动发现服务提供者,必须手动注册:
- 执行
composer require "tymon/jwt-auth:2.0.*"(注意:不是原版jwt-auth,而是社区维护的兼容版本) - 运行
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"生成配置文件config/jwt.php - 在
config/app.php的providers数组中添加:Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
- 在
app/Providers/AuthServiceProvider.php的boot()方法中添加:JWTAuth::factory()->setUserModel(User::class);
定义登录接口并生成 Token
不能直接调用 JWTAuth::attempt() 而不验证字段——它默认只检查 email 和 password,若你的用户表用的是 username 或其他字段,必须先重写 User 模型的 getJWTIdentifier() 和 getJWTCustomClaims(),否则会返回空 Token 或 "token_not_provided" 错误。
- 确保
User模型实现了Tymon\JWTAuth\Contracts\JWTSubject接口 - 登录控制器中使用标准验证逻辑:
use Tymon\JWTAuth\Facades\JWTAuth;
public function login(Request $request) { $credentials = $request->only('email', 'password'); if (!$token = JWTAuth::attempt($credentials)) { return response()->json(['error' => 'invalid_credentials'], 401); } return response()->json(compact('token')); }
- 注意:Laravel 10 默认启用严格 CSRF 保护,API 路由需放在
routes/api.php并确认中间件是api组(不含VerifyCsrfToken)
刷新 Token 时必须传入旧 Token 并校验有效期
JWTAuth::refresh() 不会自动从请求头读取 Token,必须显式传递;且刷新失败常见原因不是代码写错,而是 Token 已过期(ttl 过短)或被加入黑名单(blacklist_enabled 为 true 且未正确清除)。
- 刷新接口示例:
public function refresh() { try { $newToken = JWTAuth::refresh(); // 自动从 Authorization header 读取 Bearer Token } catch (\Exception $e) { return response()->json(['error' => 'token_invalid'], 401); } return response()->json(compact('newToken')); } - 确保
config/jwt.php中'blacklist_enabled' => true,且刷新后旧 Token 被加入黑名单(这是默认行为) - 若需延长有效时间,调整
'ttl' => 60(分钟)和'refresh_ttl' => 20160(14 天),但注意refresh_ttl必须 ≥ttl
中间件验证失败时容易忽略的 Header 格式问题
前端必须在请求头中传入 Authorization: Bearer ,少一个空格、多一个引号、或用了双引号包裹 token,都会导致 token_not_provided 或 token_expired 报错,而 Laravel 日志里不会明确提示格式问题。
- 验证中间件(如
auth:api)底层调用的是JWTGuard,它依赖Request::bearerToken()提取 token - 测试时可用 curl 手动验证:
curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." http://localhost:8000/api/user
- 若用 axios,确保设置:
axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
- Apache 服务器需额外配置,否则 Authorization header 会被丢弃:
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
JWT 的 stateless 特性意味着所有校验都发生在应用层,没有 session 存储开销,但代价是无法主动使 Token 失效(除非用黑名单),且刷新逻辑必须与前端配合严格对齐——Token 过期时间、刷新窗口、错误重试策略,任何一个环节没对上,用户就会卡在“登录成功却无法访问接口”的状态。










