尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

【基于 Swoole+Hyperf 的微服务实战】 第五周·周二:JWT 签发与验证 + 网关统一鉴权

【基于 Swoole+Hyperf 的微服务实战】 第五周·周二:JWT 签发与验证 + 网关统一鉴权 今天的主题是JWT 签发与验证 网关统一鉴权。昨天我们搭建了 API 网关实现了基本的路由转发。今天要为网关注入“安全灵魂”所有客户端请求都必须携带有效的 JWT网关层完成校验并解析出用户信息然后将这些信息通过请求头透明地传递给下游微服务。这样后端服务不再需要各自处理认证逻辑实现单点认证、全链路信任。今日目标理解 JWT 的构成、签名原理以及无状态认证的优劣。在网关项目中集成hyperf/jwt组件实现登录接口签发 Token。编写JWT 校验中间件部署在网关全局拦截未授权请求。实现用户信息透传将 JWT 解析出的用户 ID、用户名等信息注入到下游请求头如X-User-Id。修改后端hyperf-app中的控制器从请求头获取用户信息验证全链路认证。一、环境准备约 20 分钟继续使用两个项目hyperf-gateway网关9500和hyperf-app业务服务9501。确保两者都已启动。进入网关项目容器docker-composeexecswoolebashcd/var/www/hyperf-gateway安装 JWT 组件composerrequire hyperf/jwt发布 JWT 配置文件php bin/hyperf.php vendor:publish hyperf/jwt这会在config/autoload/jwt.php生成配置我们后续修改。后端hyperf-app也需要能接收和解析头部信息但不需再独立校验 JWT除非作为备选今天主要是在网关层完成。二、知识核心JWT 与无状态认证约 1 小时1. JWT 是什么JWTJSON Web Token由三部分组成Header.Payload.Signature用点号分隔经 Base64URL 编码。Header包含算法类型如 HS256和 Token 类型。Payload声明的数据包含用户信息如sub、iss、exp以及自定义字段如user_id。Signature对前两部分的签名使用服务端密钥防止篡改。网关只需在收到请求时验证签名和有效期解析出用户信息即可信任该请求来自合法用户。2. 网关鉴权的优势单一职责业务服务不再关心认证逻辑专注业务。安全集中密钥只在网关管理后端无需接触密钥。透传信任网关将认证后的用户信息通过请求头内部网络传递给后端后端默认信任。无状态扩展任何服务实例都不需要保存 Session天然适合分布式。3. 透传用户信息的方式网关在校验通过后将用户信息放入请求头例如X-User-Id: 123 X-User-Name: admin X-User-Email: adminexample.com后端服务从这些标准化的头中获取当前用户身份不再解析 JWT。为防止恶意伪造网关应当剥离原始 Authorization 头并在严格的内网防火墙下运行。三、实战构建网关鉴权体系约 2.5 小时步骤 1配置 JWT编辑config/autoload/jwt.php设置密钥和有效期?phpreturn[secretenv(JWT_SECRET,hyperf-secret-key-change-in-production),keys[// ...],ttl3600,// Token 有效期 1 小时algHS256,aud,iss,leeway60,required_claims[iss,],persistent_claims[// ...],];在.env中设定JWT_SECRET生产环境必须更换强密钥。步骤 2创建用户登录接口模拟在网关项目中新建控制器app/Controller/AuthController.php负责签发 JWT?phpnamespaceApp\Controller;useHyperf\HttpServer\Annotation\Controller;useHyperf\HttpServer\Annotation\RequestMapping;useHyperf\Di\Annotation\Inject;useHyperf\Jwt\JwtFactory;useHyperf\Jwt\Token;#[Controller(prefix:/auth)]classAuthControllerextendsAbstractController{#[Inject]privateJwtFactory$jwtFactory;#[RequestMapping(path:login,methods:post)]publicfunctionlogin(){$username$this-request-input(username);$password$this-request-input(password);// 模拟用户认证实际应调用用户服务if($username!admin||$password!123456){return$this-response-json([code401,message用户名或密码错误])-withStatus(401);}$userData[id1,usernameadmin,emailadminexample.com,];// 签发 Token$token$this-jwtFactory-make($userData);return[code200,message登录成功,data[token(string)$token,user$userData,]];}}注意这是网关自带的登录接口实际项目可以从 SSO 服务获取今天简单处理。步骤 3创建 JWT 鉴权中间件创建app/Middleware/JwtAuthMiddleware.php?phpnamespaceApp\Middleware;useHyperf\Jwt\JwtFactory;useHyperf\Di\Annotation\Inject;usePsr\Http\Message\ResponseInterface;usePsr\Http\Message\ServerRequestInterface;usePsr\Http\Server\MiddlewareInterface;usePsr\Http\Server\RequestHandlerInterface;classJwtAuthMiddlewareimplementsMiddlewareInterface{#[Inject]privateJwtFactory$jwtFactory;// 白名单路径不需要认证privatearray$whitelist[/auth/login,];publicfunctionprocess(ServerRequestInterface$request,RequestHandlerInterface$handler):ResponseInterface{$uri$request-getUri()-getPath();if(in_array($uri,$this-whitelist)){return$handler-handle($request);}$token$request-getHeaderLine(Authorization);// 通常格式为 Bearer tokenif(empty($token)||!str_starts_with($token,Bearer )){return$this-unauthorizedResponse(缺少令牌);}$tokensubstr($token,7);try{$jwt$this-jwtFactory-make($token);// 如果 Token 无效或过期会抛出异常if(!$jwt-validate()){return$this-unauthorizedResponse(令牌无效);}// 获取载荷中的用户信息$claims$jwt-getClaims();}catch(\Throwable$e){return$this-unauthorizedResponse(令牌解析失败: .$e-getMessage());}// 将用户信息注入请求属性供网关后续使用并添加到下游头$request$request-withAttribute(user_id,$claims[id]??null);$request$request-withAttribute(username,$claims[username]??null);// 传递到下游微服务的头可以在转发中间件里从属性读取并设置$request$request-withAttribute(downstream_headers,[X-User-Id(string)($claims[id]??),X-User-Name$claims[username]??,X-User-Email$claims[email]??,]);return$handler-handle($request);}privatefunctionunauthorizedResponse(string$msg):ResponseInterface{return\Hyperf\Utils\ApplicationContext::getContainer()-get(\Hyperf\HttpServer\Contract\ResponseInterface::class)-json([code401,message$msg])-withStatus(401);}}步骤 4修改转发中间件透传用户信息头打开app/Middleware/GatewayMiddleware.php在转发请求时注入下游头// 获取下游头信息由 JwtAuthMiddleware 设置$downstreamHeaders$request-getAttribute(downstream_headers,[]);// 合并到转发请求头中$headersarray_merge($request-getHeaders(),$downstreamHeaders);// 移除原始的 Authorization 头防止后端误用unset($headers[Authorization]);// ... 在 client-request 中使用 $headers修改client-request调用$response$client-request($request-getMethod(),$targetUrl,[headers$headers,body(string)$request-getBody(),timeout5,]);步骤 5调整中间件顺序在config/autoload/middlewares.php中注册中间件注意顺序JWT 鉴权优先于网关转发http[\App\Middleware\JwtAuthMiddleware::class,\App\Middleware\GatewayMiddleware::class,],步骤 6在后端业务服务中接收用户信息切换到hyperf-app项目修改某个控制器如ArticleController从请求头获取透传的用户 IDpublicfunctionstore(){$userId$this-request-getHeaderLine(X-User-Id);if(!$userId){return$this-response-json([code401,message未登录])-withStatus(401);}// 创建文章时可保存 author_id $userId// ...}这样就可以不依赖本地 Session完全信任网关传递的身份。四、成果测试与验证约 1 小时1. 测试清单检验项方法通过标准登录接口获取 Tokencurl -X POST http://localhost:9500/auth/login -d usernameadminpassword123456返回 Token无 Token 访问受保护路由curl http://localhost:9500/articles返回 401提示缺少令牌携带有效 Token 访问curl -H Authorization: Bearer token http://localhost:9500/articles返回文章列表后端能获取到用户信息无效 Token随意编造 Token返回 401解析失败过期 Token修改 JWT TTL 为 1 秒等待后访问返回 401令牌过期白名单路径不受限curl http://localhost:9500/auth/login正常访问后端服务收到透传头在后端控制器中打印X-User-Id观察日志打印出正确用户 ID后端不再直接解析 JWT发送未带 Authorization 头但带X-User-Id的请求到后端直连后端可以根据头信任需额外逻辑2. 安全验证确保网关在转发时已经剥离了Authorization头防止后端收到原始的认证信息。测试curl-HAuthorization: Bearer valid-tokenhttp://localhost:9500/articles在后端服务中打印收到的所有请求头确认Authorization头不存在。3. 性能考虑JWT 解析是 CPU 密集操作HS256 或 RS256但 Hyperf 协程化后性能尚可。对于极高并发可考虑将 JWT 缓存到 Redis 减少解析但会引入状态管理。五、今日作业与学习产出提交代码将网关的AuthController、JwtAuthMiddleware、修改后的GatewayMiddleware及后端的对应修改提交到 Git。增强鉴权实现角色权限控制在 JWT 中加入role字段网关中间件检查特定路径需要的角色如/admin/*需要roleadmin。增加Token 刷新接口允许客户端用旧 Token 换取新 Token需引入 Refresh Token 机制。学习笔记绘制完整的认证时序图客户端登录 → 网关签发 JWT → 请求带 Token → 网关验证 → 透传用户信息 → 后端服务处理。对比 JWT 与 OAuth2 的适用场景为什么微服务内部使用 JWT 更轻量。挑战任务尝试使用**非对称加密RS256**签发 JWT网关持有公钥即可验证避免密钥泄露风险。研究Hyperf 的 JWT 黑名单机制实现强制用户下线如修改密码后使旧 Token 失效。通过今天的学习你的网关已经具备了企业级的认证安全能力所有后端微服务都可以在安全无虞的环境下只关注业务。明天我们将为网关增加限流和熔断继续加固这个统一入口。
返回列表