Spomky Labs JWT框架验证Azure AD的id_token耗时过长问题咨询
验证Azure AD通过Open ID Connect(OIDC)提供的id_token签名时,单条令牌的验证处理耗时极长(约42秒),这严重影响用户认证体验,还需延长代码最大执行时间限制。我使用Spomky Labs提供的PHP JWT框架,可通过以下代码复现问题(令牌内容已脱敏):
use Jose\Component\Core\AlgorithmManager; use Jose\Component\Signature\JWSVerifier; use Jose\Component\Core\JWK; use Jose\Component\Signature\Serializer\JWSSerializerManager; use Jose\Component\Signature\Serializer\CompactSerializer; use Jose\Component\Signature\Algorithm\RS256; $algorithmManager = new AlgorithmManager([new RS256()]); $publicKey = json_decode('{"kty":"RSA","use":"sig","kid":"-KI3Q9nNR7bRofxmeZoXqbHZGew","x5t":"-KI3Q9nNR7bRofxmeZoXqbHZGew","n":"tJL6Wr2JUsxLyNezPQh1J6zn6wSoDAhgRYSDkaMuEHy75VikiB8wg25WuR96gdMpookdlRvh7SnRvtjQN9b5m4zJCMpSRcJ5DuXl4mcd7Cg3Zp1C5-JmMq8J7m7OS9HpUQbA1yhtCHqP7XA4UnQI28J-TnGiAa3viPLlq0663Cq6hQw7jYo5yNjdJcV5-FS-xNV7UHR4zAMRruMUHxte1IZJzbJmxjKoEjJwDTtcd6DkI3yrkmYt8GdQmu0YBHTJSZiz-M10CY3LbvLzf-tbBNKQ_gfnGGKF7MvRCmPA_YF_APynrIG7p4vPDRXhpG3_CIt317NyvGoIwiv0At83kQ","e":"AQAB","x5c":["MIIDBTCCAe2gAwIBAgIQGQ6YG6NleJxJGDRAwAd/ZTANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTIyMTAwMjE4MDY0OVoXDTI3MTAwMjE4MDY0OVowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALSS+lq9iVLMS8jXsz0IdSes5+sEqAwIYEWEg5GjLhB8u+VYpIgfMINuVrkfeoHTKaKJHZUb4e0p0b7Y0DfW+ZuMyQjKUkXCeQ7l5eJnHewoN2adQufiZjKvCe5uzkvR6VEGwNcobQh6j+1wOFJ0CNvCfk5xogGt74jy5atOutwquoUMO42KOcjY3SXFefhUvsTVe1B0eMwDEa7jFB8bXtSGSc2yZsYyqBIycA07XHeg5CN8q5JmLfBnUJrtGAR0yUmYs/jNdAmNy27y83/rWwTSkP4H5xhihezL0QpjwP2BfwD8p6yBu6eLzw0V4aRt/wiLd9ezcrxqCMIr9ALfN5ECAwEAAaMhMB8wHQYDVR0OBBYEFJcSH+6Eaqucndn9DDu7Pym7OA8rMA0GCSqGSIb3DQEBCwUAA4IBAQADKkY0PIyslgWGmRDKpp/5PqzzM9+TNDhXzk6pw8aESWoLPJo90RgTJVf8uIj3YSic89m4ftZdmGFXwHcFC91aFe3PiDgCiteDkeH8KrrpZSve1pcM4SNjxwwmIKlJdrbcaJfWRsSoGFjzbFgOecISiVaJ9ZWpb89/+BeAz1Zpmu8DSyY22dG/K6ZDx5qNFg8pehdOUYY24oMamd4J2u2lUgkCKGBZMQgBZFwk+q7H86B/byGuTDEizLjGPTY/sMms1FAX55xBydxrADAer/pKrOF1v7Dq9C1Z9QVcm5D9G4DcenyWUdMyK43NXbVQLPxLOng51KO9icp2j4U7pwHP"],"issuer":"https://login.microsoftonline.com/common/v2.0"}', true); $token = "<<CONTENT_REDACTED>>"; $jwk = new JWK($publicKey); $jwsVerifier = new JWSVerifier($algorithmManager); $serializerManager = new JWSSerializerManager([new CompactSerializer()]); $jws = $serializerManager->unserialize($token); $isVerified = $jwsVerifier->verifyWithKey($jws, $jwk, 0);
运行环境:Centos Stream 9系统、PHP 8.2.5版本、2核16GB内存的虚拟机。请问该耗时情况是否正常?
回答
42秒的验证耗时完全不正常,正常情况下RS256算法的JWT签名验证应该在毫秒级完成。以下是可能的原因及解决方案:
缺失OpenSSL扩展:Spomky Labs的JWT库默认依赖
ext-openssl做底层加密运算,如果未安装该扩展,库会退回到纯PHP实现,性能会暴跌几个数量级。执行php -m | grep openssl检查扩展是否加载,若未加载需安装并启用。证书链额外验证开销:你提供的JWK包含
x5c证书链,库可能在验证签名前自动执行了证书链的有效性校验。可以尝试仅使用n和e参数创建简化版JWK,跳过证书相关逻辑,测试是否提速。系统加密性能瓶颈:虽然虚拟机配置为2核16GB,但可能系统的libcrypto库性能受限,或虚拟机CPU被宿主系统限制。执行
openssl speed rsa2048测试基准性能,正常情况下2048位RSA签名验证每秒应能完成数千次。库版本问题:检查Spomky Labs的jose-php框架是否为最新稳定版,旧版本可能存在性能bug。通过
composer update web-token/jwt-framework更新到最新版。代码优化点:
- 缓存JWK对象:不要每次验证都重新解析JSON并创建JWK,将公钥缓存起来重复使用。
- 复用全局实例:AlgorithmManager、JWSVerifier、JWSSerializerManager这些对象可以全局初始化一次,无需每次请求都重新创建。
内容的提问来源于stack exchange,提问作者TomBertie

