swoole方案 统一鉴权与鉴权代理中心
?php/** * 鉴权代理网关 * * 大白话流程 * 请求进来 → 验JWT → 通过了 → 转发给PHP-FPM后端 * → 不通过 → 直接拒绝后端根本看不到这个请求 * * 为什么这么做 * PHP-FPM 每个请求都要启动框架、连数据库验token很慢 * Swoole 常驻内存JWT验证是纯计算不需要查数据库极快 * 把鉴权前置非法请求在门口就挡掉FPM只处理合法请求 * * 依赖 * composer require firebase/php-jwt * * 运行 * php8.4 auth.php */require__DIR__./vendor/autoload.php;useFirebase\JWT\JWT;useFirebase\JWT\Key;useFirebase\JWT\ExpiredException;useFirebase\JWT\SignatureInvalidException;useSwoole\Http\Server;useSwoole\Http\Request;useSwoole\Http\Response;useSwoole\Coroutine\Http\Client;// JWT 签名密钥生产环境换成长随机字符串或RSA公钥constJWT_SECRETyour-secret-key-change-this;// 不需要鉴权的白名单路径constWHITE_LIST[/login,/register,/healthz];// 后端 PHP-FPM 地址通常是 nginxfpm或直接 fpm 的 fastcgi 端口// 这里用 HTTP 方式转发假设后端是个普通 HTTP 服务constBACKEND_HOST127.0.0.1;constBACKEND_PORT8080;$servernewServer(0.0.0.0,9300);$server-set([worker_numswoole_cpu_num(),enable_coroutinetrue,]);$server-on(request,function(Request$req,Response$res){$path$req-server[request_uri];// ── 白名单直接放行不验token ──────────────────────────if(in_array($path,WHITE_LIST,true)){forward($req,$res,null);return;}// ── 从 Header 里拿 token ──────────────────────────────────// 标准格式Authorization: Bearer eyJhbGci...$authHeader$req-header[authorization]??;if(!str_starts_with($authHeader,Bearer )){deny($res,401,missing token);return;}$tokensubstr($authHeader,7);// ── 验证 JWT ──────────────────────────────────────────────// JWT 是三段 base64头.载荷.签名// 验签名 用密钥重新算一遍和第三段对比不一样就是伪造的// 验过期 载荷里有 exp 字段和当前时间比// 这两步都是纯计算不查数据库微秒级try{$payloadJWT::decode($token,newKey(JWT_SECRET,HS256));}catch(ExpiredException$e){deny($res,401,token expired);return;}catch(SignatureInvalidException$e){deny($res,401,invalid token);return;}catch(\Throwable$e){deny($res,401,bad token);return;}// ── 验通过把用户信息透传给后端 ─────────────────────────// 后端直接从 Header 读不用再验一遍forward($req,$res,$payload);});// 转发请求到后端functionforward(Request$req,Response$res,?object$payload):void{$cnewClient(BACKEND_HOST,BACKEND_PORT);$c-set([timeout10]);$headers$req-header??[];// 把解析出来的用户信息塞进 Header后端直接用if($payload){$headers[x-user-id](string)($payload-sub??);$headers[x-user-role](string)($payload-role??);$headers[x-user-name](string)($payload-name??);}// 防止后端被伪造删掉原始 Authorization换成内网信任标记unset($headers[authorization]);$headers[x-auth-verified]1;$c-setHeaders($headers);$c-setMethod($req-server[request_method]);$body$req-rawContent();if($body!$body!false){$c-setData($body);}$qs$req-server[query_string]??;$uri$req-server[request_uri].($qs!??$qs:);$c-execute($uri);if($c-statusCode0){$res-status(502);$res-end(json_encode([errorbackend unavailable]));$c-close();return;}$res-status($c-statusCode);foreach($c-headers??[]as$k$v){$res-header($k,$v);}$res-end($c-body);$c-close();}// 拒绝请求functiondeny(Response$res,int$code,string$msg):void{$res-status($code);$res-header(Content-Type,application/json);$res-end(json_encode([error$msg]));}$server-on(workerStart,function($s,$wid){if($wid0)echoAuth Gateway → http://0.0.0.0:9300\n;});$server-start();装依赖跑起来cd/mnt/d/auth composerrequirefirebase/php-jwt php8.4auth.php 测试没有token被拒 curl http://localhost:9300/api/user生成一个测试token验证通过 php8.4-r require vendor/autoload.php; echo \Firebase\JWT\JWT::encode( [sub123,roleadmin,name张三,exptime()3600], your-secret-key-change-this, HS256 ); 把输出的token带上请求 curl-HAuthorization: Bearer 上面的tokenhttp://localhost:9300/api/user---大白话解释JWT是什么 三段 base64 拼起来的字符串头.载荷.签名-头说明用什么算法-载荷用户信息比如用户ID、角色、过期时间明文的任何人都能解开看-签名用密钥把前两段算一遍防止有人篡改载荷 验证时只需重新算一遍签名对比不查数据库纯计算极快。 为什么删掉 Authorization 换成 x-auth-verified 后端服务在内网如果直接透传 Authorization后端还要再验一遍浪费。换成 x-auth-verified:1加上解析好的用户信息后端直接读x-user-id 就行信任网关已经验过了。 白名单/login/register 不需要token直接放行转发给后端。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2442326.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!