Slim Framework集成JWT认证Postman测试问题求助
看起来你在JWT配置和中间件顺序上踩了几个小坑,我帮你一步步梳理:
一、先排查"Token not found"的核心问题
你的代码里有两个关键冲突/顺序问题:
中间件顺序颠倒:你先添加了JWT验证中间件,再添加了把Query参数
token转为Authorization头的中间件。Slim的中间件是按添加顺序执行的,这意味着JWT验证在你转换Token之前就已经执行了,自然找不到Token。
👉 解决方案:把Query转Header的中间件放在JWT中间件之前。JWT中间件配置冲突:你同时设置了
"header" => "X-Token"和"environment" => "HTTP_X_TOKEN",还额外处理了Authorization头,导致Token的读取逻辑混乱。建议统一用标准的Authorization: Bearer <token>头,简化配置。secure: true的限制:如果你的本地开发环境是HTTP(非HTTPS),这个配置会导致JWT中间件拒绝非HTTPS请求的Token,本地测试可以先改成"secure" => false,上线再改回true。
调整后的中间件顺序和配置示例:
// 先处理Query参数转Header(可选,方便快速测试) $app->add(function($request, $response, $next) { $queryParams = $request->getQueryParams(); if (!empty($queryParams["token"])) { $request = $request->withHeader("Authorization", "Bearer {$queryParams["token"]}"); } return $next($request, $response); }); // 再添加JWT认证中间件 $app->add(new \Slim\Middleware\JwtAuthentication([ "path" => "/api", "passthrough" => ["/api/token", "/admin/ping"], "secure" => false, // 本地开发用false,上线改为true "header" => "Authorization", // 用标准的Authorization头 "regexp" => "/Bearer\s+(.*)$/i", // 匹配Bearer Token的规则 "secret" => "supersecretkeyyoushouldnotcommittogithub", "callback" => function ($request, $response, $arguments) use ($container) { $container["jwt"] = $arguments["decoded"]; }, "error" => function ($request, $response, $arguments) { $data["status"] = "error"; $data["message"] = $arguments["message"]; return $response ->withHeader("Content-Type", "application/json") ->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); } ]));
二、你还缺少的JWT实现步骤
目前你的代码只有JWT验证逻辑,没有生成Token的接口,这是关键缺失项:
安装JWT依赖库:Slim的JwtAuthentication中间件依赖
firebase/php-jwt,通过Composer安装:composer require firebase/php-jwt实现Token生成接口(/api/token):这个接口用你已经验证通过的Basic Auth校验用户,然后签发JWT。示例代码:
use Firebase\JWT\JWT; $app->post('/api/token', function(Request $request, Response $response) { // 复用你已有的Basic Auth验证逻辑 $authHeader = $request->getHeaderLine('Authorization'); if (!preg_match('/Basic\s+(.*)$/i', $authHeader, $matches)) { return $response->withStatus(401)->write(json_encode(["error" => "Basic Auth required"])); } $userPass = base64_decode($matches[1]); list($username, $password) = explode(':', $userPass); // 替换成你的数据库用户校验逻辑 if ($username !== "valid_user" || $password !== "valid_pass") { return $response->withStatus(401)->write(json_encode(["error" => "Invalid credentials"])); } // 签发JWT,设置过期时间等参数 $payload = [ "iss" => "your_app_name", // 签发者标识 "iat" => time(), // 签发时间 "exp" => time() + 3600, // 1小时后过期 "username" => $username // 自定义用户信息 ]; $jwt = JWT::encode($payload, "supersecretkeyyoushouldnotcommittogithub"); return $response->withJson(["token" => $jwt]); });
三、Postman测试步骤
步骤1:获取Token
- 打开Postman,新建POST请求,URL填写
http://你的本地地址/api/token - 切换到Authorization标签,Type选择
Basic Auth,输入你已验证通过的用户名和密码 - 点击Send,会收到包含
token字段的JSON响应,复制这个Token
步骤2:测试带JWT的API请求(比如GET /api/customers)
有两种传递Token的方式,选一种即可:
方式1:用Authorization头(推荐)
- 新建GET请求,URL填写
http://你的本地地址/api/customers - 切换到Headers标签,添加Key为
Authorization,Value为Bearer <你的Token>(注意Bearer后面有空格) - 点击Send,应该能正常返回数据
方式2:用Query参数(快速测试)
- 新建GET请求,URL填写
http://你的本地地址/api/customers?token=<你的Token> - 直接点击Send,中间件会自动把Query参数转为Authorization头
注意事项
- 确保你的
.htaccess配置正确,已经传递了HTTP_AUTHORIZATION环境变量(你现有配置是对的):RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}] - 如果仍有问题,打开Postman的Console查看请求头是否正确发送,或者在中间件里加日志输出调试Token是否被正确读取。
内容的提问来源于stack exchange,提问作者pancy1

