You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows EC2上aws-jwt-verify获取JWKS超时,替代方案咨询

问题背景

我们有一个Express项目,通过aws-jwt-verify npm包实现Token验证路由。代码在Mac与Linux机器上运行正常,但部署至Windows EC2实例并使用pm2进程管理器运行时,出现功能异常并抛出超时错误。

原代码

const { CognitoJwtVerifier } = require('aws-jwt-verify');
class TokenVerificationSvc {
    constructor() {
    }

    async verify(token, type = 'id') {
        const docClient = new CognitoJwtVerifier({
            userPoolId: process.env.SApplicationUsersPool,
            tokenUse: type,
            clientId: process.env.SApplicationUsersPoolClient,
        });
        return await docClient.verify(token);
    }
}

module.exports = { TokenVerificationSvc };

错误信息

Failed to fetch https://cognito-idp.ap-south-1.amazonaws.com/.well-known/jwks.json: Response time-out (after 1500 ms.)

改进后代码

const { CognitoJwtVerifier } = require('aws-jwt-verify');
const axios = require('axios');
class TokenVerificationSvc {
    constructor() {
    }

    async verify(token, type = 'id') {
        const jwksResponse = await axios.get(`https://cognito-idp.${process.env.CLOUD_REGION}.amazonaws.com/${process.env.SApplicationUsersPool}/.well-known/jwks.json`)
        const docClient = new CognitoJwtVerifier({
            userPoolId: process.env.SApplicationUsersPool,
            tokenUse: type,
            clientId: process.env.SApplicationUsersPoolClient,
        });
        const jwks = jwksResponse.data;
        docClient.cacheJwks(jwks);
        return await docClient.verify(token);
    }
}

module.exports = { TokenVerificationSvc };

疑问

  1. 上述实现方式是否合理?
  2. 是否存在不依赖axios等第三方请求包的替代方案?

解答

关于实现合理性

当前改进方案存在明显不合理的地方,核心问题如下:

  • 重复创建Verifier实例:每次调用verify都新建CognitoJwtVerifier,cacheJwks的缓存完全无法在多次请求间复用,本质还是每次验证都重复发起JWKS请求,没有发挥缓存作用。
  • 无错误处理与超时控制:axios请求JWKS时没有异常捕获和超时配置,一旦请求失败会直接中断验证流程。
  • 无缓存过期策略:没有对JWKS做持久化缓存,每次验证都重新请求,既增加延迟也浪费资源,还可能触发AWS请求限制。

合理的优化方向:

  • 将CognitoJwtVerifier改为单例,在类初始化时创建一次,而非每次验证都新建。
  • 对获取到的JWKS添加本地缓存和过期刷新逻辑(JWKS不会频繁更新,建议设置1小时左右的有效期)。
  • 为HTTP请求添加超时、重试和异常捕获,适配Windows EC2的网络环境。

不依赖第三方请求包的替代方案

可以直接使用Node.js内置的https模块获取JWKS,无需引入axios,同时优化整体实现逻辑:

优化后的单例实现(使用内置https)

const { CognitoJwtVerifier } = require('aws-jwt-verify');
const https = require('https');
const { promisify } = require('util');

// 将https.get转为Promise形式,方便异步调用
const httpsGet = promisify(https.get);

class TokenVerificationSvc {
    constructor() {
        // 初始化Verifier单例
        this.verifier = new CognitoJwtVerifier({
            userPoolId: process.env.SApplicationUsersPool,
            tokenUse: 'id',
            clientId: process.env.SApplicationUsersPoolClient,
        });
        // 缓存JWKS和过期时间
        this.cachedJwks = null;
        this.jwksExpiry = 0;
        // JWKS缓存有效期(1小时)
        this.JWKS_TTL = 3600 * 1000;
    }

    async fetchJwks() {
        const url = `https://cognito-idp.${process.env.CLOUD_REGION}.amazonaws.com/${process.env.SApplicationUsersPool}/.well-known/jwks.json`;
        try {
            const req = await httpsGet(url, { timeout: 5000 }); // 设置5秒超时
            let data = '';
            for await (const chunk of req) {
                data += chunk;
            }
            return JSON.parse(data);
        } catch (err) {
            throw new Error(`获取JWKS失败: ${err.message}`);
        }
    }

    async ensureJwksCached() {
        const now = Date.now();
        // 缓存不存在或已过期时重新获取
        if (!this.cachedJwks || now > this.jwksExpiry) {
            this.cachedJwks = await this.fetchJwks();
            this.jwksExpiry = now + this.JWKS_TTL;
            // 更新Verifier的JWKS缓存
            this.verifier.cacheJwks(this.cachedJwks);
        }
    }

    async verify(token, type = 'id') {
        await this.ensureJwksCached();
        // 支持动态切换token类型
        if (type !== this.verifier.options.tokenUse) {
            this.verifier = new CognitoJwtVerifier({
                userPoolId: process.env.SApplicationUsersPool,
                tokenUse: type,
                clientId: process.env.SApplicationUsersPoolClient,
            });
            this.verifier.cacheJwks(this.cachedJwks);
        }
        return await this.verifier.verify(token);
    }
}

module.exports = { TokenVerificationSvc };

更简单的替代方案:修改默认超时

原问题的核心是默认1500ms超时太短,Windows EC2网络延迟更高,直接修改aws-jwt-verify的fetchTimeout参数即可,无需主动获取JWKS:

const verifier = new CognitoJwtVerifier({
    userPoolId: process.env.SApplicationUsersPool,
    tokenUse: 'id',
    clientId: process.env.SApplicationUsersPoolClient,
    fetchTimeout: 5000 // 改为5秒超时
});

建议优先尝试这个方案,若仍有问题再考虑主动缓存JWKS。

额外排查点

确认Windows EC2实例的安全组、网络ACL是否允许出站访问Cognito服务地址,这也是常见的网络超时原因。

内容的提问来源于stack exchange,提问作者sandeepmaity

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 11:58:09