Laravel如何使用JWT进行用户认证_Laravel集成jwt-auth插件与Token刷新【方法】

12次阅读

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

Laravel如何使用JWT进行用户认证_Laravel集成jwt-auth插件与Token刷新【方法】

JWT 认证在 Laravel 中不是开箱即用的,必须通过 laravel/jwt-auth(已停止维护)或更现代的替代方案(如 tymon/jwt-auth 的社区维护分支 php-jwt/jwt-auth)实现;当前推荐直接使用 laravel/sanctumlaravel/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="TymonJWTAuthProvidersLaravelServiceProvider" 生成配置文件 config/jwt.php
  • config/app.phpproviders 数组中添加:
    TymonJWTAuthProvidersLaravelServiceProvider::class,
  • app/Providers/AuthServiceProvider.phpboot() 方法中添加:
    JWTAuth::factory()->setUserModel(User::class);

定义登录接口并生成 Token

不能直接调用 JWTAuth::attempt() 而不验证字段——它默认只检查 emailpassword,若你的用户表用的是 username 或其他字段,必须先重写 User 模型的 getJWTIdentifier()getJWTCustomClaims(),否则会返回空 Token 或 "token_not_provided" 错误。

  • 确保 User 模型实现了 TymonJWTAuthContractsJWTSubject 接口
  • 登录控制器中使用标准验证逻辑:
    use TymonJWTAuthFacadesJWTAuth; 

    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_providedtoken_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 过期时间、刷新窗口、错误重试策略,任何一个环节没对上,用户就会卡在“登录成功却无法访问接口”的状态。

text=ZqhQzanResources