无法在无服务器和 DynamoDB/Cognito/API 网关的 lambda 策略中使用 ${cognito-identity.amazonaws.com:sub}

2023-12-13

客观的:

  1. 使用 Cognito 进行身份验证(使用下面的 serverless.yml 配置)
  2. 点击经过身份验证的端点 GET /users 以触发 lambda 作业。
  3. 基于IAM策略,限制基于cognito用户查询的DynamoDB表的访问cognito-identity.amazonaws.com:sub使用LeadingKey条件。

问题:我的策略似乎没有填充认知变量${cognito-identity.amazonaws.com:sub}。如果我手动指定dynamodb:LeadingKeys有了一个值,它就可以正常工作。所以看来我只需要 Cognito 正确填充子值,我已经到处寻找但找不到解决方案。

我的 lambda 角色/策略(将生成的无服务器版本修改为具有包含 Cognito 和 DynamoDB 规则的信任策略):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:CreateLogStream",
                "logs:CreateLogGroup"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:xxx:log-group:/aws/lambda/exeampleservice*:*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:xxxx:log-group:/aws/lambda/exampleservice*:*:*"
            ],
            "Effect": "Allow"
        },
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:PutItem",
                "dynamodb:GetItem",
                "dynamodb:Query"
            ],
            "Resource": "*",
            "Condition": {
                "ForAllValues:StringEquals": {
                    "dynamodb:LeadingKeys": "${cognito-identity.amazonaws.com:sub}"
                }
            }
        }
    ]
}

具有信任关系:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "cognito-identity.amazonaws.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "cognito-identity.amazonaws.com:aud": "us-east-1:<identity pool id>"
        }
      }
    }
  ]
}

附加设置信息:

  • 使用带有http协议的API网关。
  • 在下面的 serverless.yml 中创建了 userPool。
  • 设置 Cognito 身份池(联合)。
  • 创建了一个 userPool 组并为其分配了我的身份池 ID。
  • 将池中的用户分配给组。
  • 使用 Cognito 和 id 进行身份验证,访问令牌显示身份 id 令牌:
{
  "sub": "xxxx",
  "cognito:groups": [
    "TestGroup"
  ],
  "email_verified": true,
  "iss": "https://cognito-idp.us-east-1.amazonaws.com/<poolid>",
  "cognito:username": "xxx",
  "cognito:roles": [
    "arn:aws:iam::xxxx:role/Cognito_IdentityPoolAuth_Role"
  ],
  "aud": "xxx",
  "event_id": "xxx",
  "token_use": "id",
  "auth_time": 1595367712,
  "exp": 1595371310,
  "iat": 1595367710,
  "email": "[email protected]"
}
  • 我的简化 Serverless.yml
org: exampleorg
app: exampleapp
service: exampleservers
provider:
  name: aws
  stage: dev
  runtime: nodejs12.x
  iamManagedPolicies:
    - 'arn:aws:iam::xxxx:policy/UserAccess'
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource:
        - { 'Fn::ImportValue': '${self:provider.stage}-UsersTableArn' }
      Condition:
        {
          'ForAllValues:StringEquals':
            { // use join to avoid conflict with serverless variable syntax. Ouputs 
              'dynamodb:LeadingKeys':
                [Fn::Join: ['', ['$', '{cognito-identity.amazonaws.com:sub}']]],
            },
        }

  httpApi:
    authorizers:
      serviceAuthorizer:
        identitySource: $request.header.Authorization
        issuerUrl:
          Fn::Join:
            - ''
            - - 'https://cognito-idp.'
              - '${opt:region, self:provider.region}'
              - '.amazonaws.com/'
              - Ref: serviceUserPool
        audience:
          - Ref: serviceUserPoolClient
functions:
  # auth
  login:
    handler: auth/handler.login
    events:
      - httpApi:
          method: POST
          path: /auth/login
          # authorizer: serviceAuthorizer

  # user
  getProfileInfo:
    handler: user/handler.get
    events:
      - httpApi:
          method: GET
          path: /user/profile
          authorizer: serviceAuthorizer
resources:
  Resources:
    HttpApi:
      DependsOn: serviceUserPool
    serviceUserPool:
      Type: AWS::Cognito::UserPool
      Properties:
        UserPoolName: service-user-pool-${opt:stage, self:provider.stage}
        UsernameAttributes:
          - email
        AutoVerifiedAttributes:
          - email
    serviceUserPoolClient:
      Type: AWS::Cognito::UserPoolClient
      Properties:
        ClientName: service-user-pool-client-${opt:stage, self:provider.stage}
        AllowedOAuthFlows:
          - implicit
        AllowedOAuthFlowsUserPoolClient: true
        AllowedOAuthScopes:
          - phone
          - email
          - openid
          - profile
          - aws.cognito.signin.user.admin
        UserPoolId:
          Ref: serviceUserPool
        CallbackURLs:
          - https://localhost:3000
        ExplicitAuthFlows:
          - ALLOW_USER_SRP_AUTH
          - ALLOW_REFRESH_TOKEN_AUTH
        GenerateSecret: false
        SupportedIdentityProviders:
          - COGNITO
    serviceUserPoolDomain:
      Type: AWS::Cognito::UserPoolDomain
      Properties:
        UserPoolId:
          Ref: serviceUserPool
        Domain: service-user-pool-domain-${opt:stage, self:provider.stage}-${self:provider.environment.DOMAIN_SUFFIX}

我已经尝试了几乎所有方法来获取变量${cognito-identity.amazonaws.com:sub}在政策中,但似乎没有任何作用。

有谁知道如何解决这个问题?或者我可能会错过什么。 (如果我错过了任何重要的内容,我将更新更多信息)。

Thanks!

编辑:(附加信息)

我的登录函数(lambda + HTTP API)如下,我通过用户/密码授权User,然后调用CognitoIdentityCredentials“注册”我的身份并从池中获取我的identityId。 (我验证我正在注册,因为身份池显示用户)

然后,我的登录调用会使用 accessToken、idToken、identityId 进行响应。

我的所有其他 API 调用都在对我进行授权的承载授权调用中使用 idToken,但似乎并未假定我的身份池的授权角色,而是使用我的 lambda 角色来执行。

我在这里缺少什么?我认为 Cognito 会处理身份验证池的假设角色,但看起来整个?任何帮助表示赞赏!

我的请求上下文(来自我的登录函数,请注意身份对象充满空值):

 requestContext: {
    accountId: 'xxx',
    apiId: 'xxx',
    domainName: 'xxxx.execute-api.us-east-1.amazonaws.com',
    domainPrefix: 'xxx',
    extendedRequestId: 'xxxx=',
    httpMethod: 'POST',
    identity: {
      accessKey: null,
      accountId: null,
      caller: null,
      cognitoAuthenticationProvider: null,
      cognitoAuthenticationType: null,
      cognitoIdentityId: null,
      cognitoIdentityPoolId: null,
      principalOrgId: null,
      sourceIp: 'xxxx',
      user: null,
      userAgent: 'PostmanRuntime/7.26.1',
      userArn: null
    },

我的登录功能

const AWS = require('aws-sdk');
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
global.fetch = require('node-fetch').default; // .default for webpack.
const USER_POOL_ID = process.env.USER_POOL_ID;
const USER_POOL_CLIENT_ID = process.env.USER_POOL_CLIENT_ID;
const USER_POOL_IDENTITY_ID = process.env.USER_POOL_IDENTITY_ID; 
console.log('USER_POOL_ID', USER_POOL_ID);
console.log('USER_POOL_CLIENT_ID', USER_POOL_CLIENT_ID);
console.log('USER_POOL_CLIENT_ID', USER_POOL_IDENTITY_ID);
 
const poolData = {
  UserPoolId: USER_POOL_ID, 
  ClientId: USER_POOL_CLIENT_ID,
};
 
const poolRegion = 'us-east-1';
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
 
function login(Username, Password) {
  var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({
    Username,
    Password,
  });
 
  var userData = {
    Username,
    Pool: userPool,
  };
  var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
 
  return new Promise((resolve, reject) => {
    cognitoUser.authenticateUser(authenticationDetails, {
      onSuccess: function (result) {
 
        AWS.config.credentials = new AWS.CognitoIdentityCredentials({
          IdentityPoolId: USER_POOL_IDENTITY_ID, // your identity pool id here
          Logins: {
            // Change the key below according to the specific region your user pool is in.
            [`cognito-idp.${poolRegion}.amazonaws.com/${USER_POOL_ID}`]: result
              .getIdToken()
              .getJwtToken(),
          },
        });
 
        //refreshes credentials using AWS.CognitoIdentity.getCredentialsForIdentity()
        AWS.config.credentials.refresh((error) => {
          if (error) {
            console.error(error);
          } else {
            // Instantiate aws sdk service objects now that the credentials have been updated.
            // example: var s3 = new AWS.S3();
            console.log('Successfully Refreshed!');
            AWS.config.credentials.get(() => {
              // return back all tokens and identityId in login call response body.
              const identityId = AWS.config.credentials.identityId;
              const tokens = {
                accessToken: result.getAccessToken().getJwtToken(),
                idToken: result.getIdToken().getJwtToken(),
                refreshToken: result.getRefreshToken().getToken(),
                identityId,
              };
              resolve(tokens);
            });
          }
        });
      },
      onFailure: (err) => {
        console.log(err);
        reject(err);
      },
    });
  });
}
module.exports = {
  login,
};

我不太清楚您是否已假定身份(将用户池中的 ID 令牌交换为 STS 令牌)。

令人困惑的是,cognito-identity.amazonaws.com:sub 解析为 ID 池身份 ID,而不是用户池中 ID 令牌中的主题 ID。请参阅本页的注释部分:https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_s3_cognito-bucket.html

要获取身份凭证,请查看https://docs.aws.amazon.com/cognitoidentity/latest/APIReference/API_GetCredentialsForIdentity.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无法在无服务器和 DynamoDB/Cognito/API 网关的 lambda 策略中使用 ${cognito-identity.amazonaws.com:sub} 的相关文章

  • 调整添加的绘制组件的大小和奇怪的摆动行为

    这个问题困扰了我好几天 我正在制作一个特殊的绘画程序 我制作了一个 JPanel 并添加了使用 Paint 方法绘制的自定义 jComponent 问题是 每当我调整窗口大小时 所有添加的组件都会 消失 或者只是不绘制 因此我最终会得到一个
  • 在 RESTful Web 服务中实现注销

    我正在开发一个需要注销服务的移动应用程序 登录服务是通过数据库验证来完成的 现在我陷入了注销状态 退一步 您没有提供有关如何在应用程序中执行身份验证的详细信息 并且很难猜测您在做什么 但是 需要注意的是 在 REST 应用程序中 不能有会话
  • 如何通过索引访问 JSON 对象中的字段

    我知道这不是最好的方法 但我别无选择 我必须通过索引访问 JSONObject 中的项目 访问对象的标准方法是只写this objectName or this objectName 我还找到了一种获取 json 对象内所有字段的方法 fo
  • MySQL 查询计算上个月

    我想计算上个月的订单总额 我收到了从当前日期获取当月数据的查询 SELECT SUM goods total AS Total Amount FROM orders WHERE order placed date gt date sub c
  • PrimeFaces 对话框参考父级

    我有一个 xhtml 页面 显示带有条目的数据表 我还有一个用于插入新条目的按钮 该按钮显示一个包含表单的对话框 插入表格用作
  • 类型或命名空间“MyNamespace”不存在等

    我有通常的类型或命名空间名称不存在错误 除了我引用了程序集 using 语句没有显示为不正确 并且我引用的类是公共的 事实上 我在不同的解决方案中引用并使用相同的程序集来执行相同的操作 并且效果很好 顺便说一句 这是VS2010 有人有什么
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • php 数组中出现意外的 json 输出结构

    我正在尝试转换动态数据 如何从 PHP 获取此 JSON JSON 122240cb 253c 4046 adcd ae81266709a6 item 0 3 这就是我所做的 但它不起作用 PHP json array 122240cb 2
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template
  • Amazon RDS for SQL Server 是否支持 SSIS?

    从谷歌搜索中读到一些相互矛盾的答案 不确定答案是是 否还是可能 我觉得读的时候已经很清楚了this http docs aws amazon com AmazonRDS latest UserGuide CHAP SQLServer htm
  • GUI Java 程序 - 绘图程序

    我一直试图找出我的代码有什么问题 这个想法是创建一个小的 Paint 程序并具有红色 绿色 蓝色和透明按钮 我拥有我能想到的让它工作的一切 但无法弄清楚代码有什么问题 该程序打开 然后立即关闭 import java awt import
  • 如何在 Angular 4 中翻译 mat-paginator?

    你知道如何在 Angular 中翻译 每页项目 吗mat paginator标签 这mat paginator是材料设计中的一个元素 您可以使用MatPaginatorIntl为了这 威尔 豪厄尔制作 https github com an
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat
  • 使用velocity.js制作可拖动元素的动画

    我正在使用velocity js 为用户拖动的可拖动 SVG 元素设置动画 然而 velocity js 将先前的 mousemove 坐标排队并通过所有后续的 mousemove 坐标进行动画处理 我想要的是velocity js 不要对
  • 如何确定 CultureInfo 实例是否支持拉丁字符

    是否可以确定是否CultureInfo http msdn microsoft com en us library system globalization cultureinfo aspx我正在使用的实例是否基于拉丁字符集 我相信你可以使
  • 如何修复:“无法解析类型 java.lang.CharSequence。它是从所需的 .class 文件间接引用的”消息? [复制]

    这个问题在这里已经有答案了 我正在尝试使用这个字符串 amountStr amountStr replace replace replace 但我收到一条错误消息 我知道我收到的错误消息是因为我刚刚发布的字符串已过时 所以我想知道该字符串的
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前
  • Android 材料芯片组件崩溃应用程序。无法膨胀 xml

    Tried Chip来自两个支持库的组件 com google android support design 28 0 0 rc01和材料 com google android material material 1 0 0 rc01 堆栈
  • 禁用允许文本选择的

    残疾人可以吗
  • PyAudio ErrNo 输入溢出 -9981

    我遇到了与用户相同的错误 Python 使用 Pyaudio 以 16000Hz 录制音频时出错 https stackoverflow com questions 12994981 python error audio recording

随机推荐