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

基于AWS Cognito的自定义Node.js API授权方案问询

嘿,我来帮你理清楚怎么用Cognito给你的Node.js API做权限管控——结合你提到的API Gateway和Lambda的话,能实现更灵活、安全的权限体系,一步步来:

1. 先搞定基础:Node.js API直接集成Cognito Token验证与权限判断

既然你已经能拿到Cognito的idToken/accessToken,第一步就是让你的API能验证这些token的合法性,再根据用户的身份信息做权限判断。

  • 第一步:验证Token有效性
    别自己手写签名验证,用成熟的库来做更靠谱。可以用jsonwebtoken结合jwks-rsa来拉取Cognito的公钥,验证token的签名、过期时间、发行方等信息。写个Express中间件就能复用:

    const jwt = require('jsonwebtoken');
    const jwksClient = require('jwks-rsa');
    
    // 替换成你的用户池信息
    const client = jwksClient({
      jwksUri: 'https://cognito-idp.<你的区域>.amazonaws.com/<你的用户池ID>/.well-known/jwks.json'
    });
    
    function getSigningKey(header, callback) {
      client.getSigningKey(header.kid, (err, key) => {
        const signingKey = key.getPublicKey();
        callback(null, signingKey);
      });
    }
    
    // 验证token的中间件
    const authenticateToken = (req, res, next) => {
      const authHeader = req.headers['authorization'];
      const token = authHeader?.split(' ')[1]; // 提取Bearer后面的token
    
      if (!token) return res.sendStatus(401); // 没有token直接返回未授权
    
      jwt.verify(token, getSigningKey, {
        audience: '<你的应用客户端ID>',
        issuer: 'https://cognito-idp.<你的区域>.amazonaws.com/<你的用户池ID>'
      }, (err, decodedUser) => {
        if (err) return res.sendStatus(403); // token无效或过期
        req.user = decodedUser; // 把解析后的用户信息挂载到req上
        next();
      });
    };
    

    把这个中间件挂在需要授权的路由前面,比如app.get('/api/protected', authenticateToken, (req, res) => { ... })。

  • 第二步:基于用户组/自定义属性做权限判断
    Cognito的用户组(User Groups)是最省心的权限划分方式——你可以在Cognito控制台创建admin、editor、viewer这类组,把用户分配进去。解析后的token里会有cognito:groups字段,直接用这个来做权限校验:

    // 验证是否为admin的中间件
    const requireAdmin = (req, res, next) => {
      if (!req.user['cognito:groups']?.includes('admin')) {
        return res.sendStatus(403); // 没有权限返回禁止访问
      }
      next();
    };
    
    // 给admin专属路由用
    app.get('/api/admin/dashboard', authenticateToken, requireAdmin, (req, res) => {
      res.send('欢迎访问admin控制面板');
    });
    

    如果需要更灵活的标记,比如给用户加custom:role这类自定义属性,原理一样,从req.user['custom:role']里取判断就行。

2. 进阶方案:用API Gateway + Lambda简化权限管控

如果你的API可以迁移到Lambda,或者用API Gateway做代理,那完全可以把token验证和权限管控交给AWS服务来做,不用自己写代码维护:

  • 步骤1:把Node.js API部署成Lambda(或用HTTP代理)
    要么把你的Node.js代码打包成Lambda函数,要么用API Gateway的HTTP代理集成,直接指向你现有的API地址。

  • 步骤2:配置Cognito授权器
    在API Gateway控制台里,给你的API添加一个Cognito用户池授权器,关联你的Cognito用户池和应用客户端。这样API Gateway会自动拦截请求,验证Authorization头里的Bearer token,无效请求直接返回401,不用你在代码里处理。

  • 步骤3:用IAM策略细化API权限
    给Cognito用户组关联不同的IAM角色,每个角色对应不同的API访问权限。比如给admin组的角色配一个允许访问所有API资源的策略,给viewer组配只允许访问GET接口的策略:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "execute-api:Invoke",
          "Resource": "arn:aws:execute-api:<区域>:<账号ID>:<API ID>/<阶段>/GET/public/*"
        },
        {
          "Effect": "Allow",
          "Action": "execute-api:Invoke",
          "Resource": "arn:aws:execute-api:<区域>:<账号ID>:<API ID>/<阶段>/*/admin/*"
        }
      ]
    }
    

    这样API Gateway会自动根据用户所属组的角色,判断是否允许访问当前请求的资源。

  • 步骤4:在Lambda里获取用户信息
    经过授权的请求,Lambda可以通过event.requestContext.authorizer.claims拿到用户的所有Cognito信息(比如组、自定义属性),然后在代码里做更细粒度的判断,比如用户只能访问自己创建的数据。

3. 超灵活方案:自定义Lambda授权器

如果需要更复杂的权限逻辑(比如基于用户拥有的资源ID、动态权限),可以用API Gateway的自定义Lambda授权器:

  • 写一个Lambda函数,接收API Gateway传来的token,验证后返回自定义的IAM策略,决定用户是否能访问当前请求的资源。
  • 比如用户要访问/api/articles/123,Lambda可以解析token里的用户ID,查询数据库确认用户是否拥有这篇文章的权限,再返回允许或拒绝的策略。
4. 别忘了处理Token刷新

accessToken过期时间短(一般1小时),所以要在前端或API拦截器里用refreshToken去Cognito获取新的accessToken和idToken,避免用户频繁登录。用amazon-cognito-identity-js的示例代码:

const { CognitoUserPool } = require('amazon-cognito-identity-js');

const userPool = new CognitoUserPool({
  UserPoolId: '<你的用户池ID>',
  ClientId: '<你的应用客户端ID>'
});

const currentUser = userPool.getCurrentUser();
if (currentUser) {
  currentUser.getSession((err, session) => {
    if (err) {
      console.error('获取会话失败:', err);
      return;
    }
    if (!session.isValid()) {
      // 用refreshToken刷新会话
      currentUser.refreshSession(session.getRefreshToken(), (err, newSession) => {
        if (err) {
          // 刷新失败,需要引导用户重新登录
          console.error('刷新会话失败:', err);
        } else {
          const newIdToken = newSession.getIdToken().getJwtToken();
          const newAccessToken = newSession.getAccessToken().getJwtToken();
          // 保存新的token到本地存储或请求头
        }
      });
    }
  });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:53:41