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)。
该包官方主仓库已归档,需使用活跃的 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);
不能直接调用 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')); }
routes
/api.php 并确认中间件是 api 组(不含 VerifyCsrfToken)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
前端必须在请求头中传入 Authorization: Bearer ,少一个空格、多一个引号、或用了双引号包裹 token,都会导致 token_not_provided 或 token_expired 报错,而 Laravel 日志里不会明确提示格式问题。
auth:api)底层调用的是 JWTGuard,它依赖 Request::bearerToken() 提取 tokencurl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..." http://localhost:8000/api/user
axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]JWT 的 stateless 特性意味着所有校验都发生在应用层,没有 session 存储开销,但代价是无法主动使 Token 失效(除非用黑名单),且刷新逻辑必须与前端配合严格对齐——Token 过期时间、刷新窗口、错误重试策略,任何一个环节没对上,用户就会卡在“登录成功却无法访问接口”的状态。