【问题标题】:Calling APPSYNC mutation from Lambda with Cognito User Pool - UnauthorizedException使用 Cognito 用户池从 Lambda 调用 APPSYNC 突变 - UnauthorizedException
【发布时间】:2019-05-14 11:58:19
【问题描述】:

我正在尝试从 Lambda 调用一个由计时器定期触发的突变。这就是我正在做的事情

const params = {
    AccountId: "XXXXXXX",
    RoleArn: "arn:aws:iam::XXXX:role/appsync_lamda_role",     // tried removing this too
    IdentityPoolId: "ap-southeast-1:xxxx-xxxx-xxx-xxxx-xxx",
    LoginId: "demo_access" // tried with and without this
};
AWS.config.update({
    region: "ap-southeast-1",
    credentials: new AWS.CognitoIdentityCredentials(params)
});

现在,我打电话给

 AWS.config.credentials.get(err => {

    const signer = new AWS.Signers.V4(httpRequest, "appsync", true);
    signer.addAuthorization(AWS.config.credentials, AWS.util.date.getDate());


 const options = {
        method: httpRequest.method,
        body: httpRequest.body,
        headers: httpRequest.headers
    };

    fetch(uri.href, options)
        .then(res => res.json())
        .then(json => {
            console.log(`JSON Response = ${JSON.stringify(json, null, 2)}`);
            callback(null, event);
        })
        .catch(err => {
            console.error(`FETCH ERROR: ${JSON.stringify(err, null, 2)}`);
            callback(err);
        });
});

当我这样做时,我从 APPSYNC 收到一个错误,称为“错误”:[ { "errorType": "UnauthorizedException", “消息”:“无法解析 JWT 令牌。” } 我已授予角色访问权限以调用 GraphQL 并编辑信任关系

 {
     "Effect": "Allow",
      "Principal": {
        "Federated": "cognito-identity.amazonaws.com"
       },
        "Action": "sts:AssumeRoleWithWebIdentity"
    }

我在这里缺少什么?请帮忙。

当我查看生成的标头时,我没有看到 JWT 令牌,但我看到了会话令牌 喜欢

 'User-Agent': 'aws-sdk-nodejs/2.275.1 linux/v8.10.0 exec-env/AWS_Lambda_nodejs8.10',
host: 'xxxxx.appsync-api.ap-southeast-1.amazonaws.com',
'Content-Type': 'application/json',
'X-Amz-Date': '20181213T080156Z',
'x-amz-security-token': 'xxxxxx//////////xxxxxEOix8u062xxxxxynf4Q08FxxxLZxV+xx/xxx/xxx/xxxxx=',
Authorization: 'AWS4-HMAC-SHA256 Credential=xxxxxxxxx/20181213/ap-southeast-1/appsync/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token, Signature=xxxxxxxxxxxxxxxxxxxxxxx' }

提前致谢

【问题讨论】:

    标签: lambda amazon-cognito aws-appsync


    【解决方案1】:

    你可以试试这个:

    import 'babel-polyfill';
    import URL from 'url';
    import fetch from 'node-fetch';
    import { CognitoIdentityServiceProvider } from 'aws-sdk';
    
    const cognitoIdentityServiceProvider = new CognitoIdentityServiceProvider({ apiVersion: '2016-04-18' });
    const initiateAuth = async ({ clientId, username, password }) => cognitoIdentityServiceProvider.initiateAuth({
        AuthFlow: 'USER_PASSWORD_AUTH',
        ClientId: clientId,
        AuthParameters: {
          USERNAME: username,
          PASSWORD: password,
        },
      })
      .promise();
    
    export const handler = async (event, context, callback) => {
      const clientId = 'YOUR_COGNITO_CLIENT_ID';
      const endPoint = 'YOUR_GRAPHQL_END_POINT_URL';
      const username = 'COGNITO_USERNAME';
      const password = 'COGNITO_PASSWORD';
      const { AuthenticationResult } = await initiateAuth({
        clientId,
        username,
        password,
      });
      const accessToken = AuthenticationResult && AuthenticationResult.AccessToken;
      const postBody = {
        query: `mutation AddUser($userId: ID!, $userDetails: UserInput!) {
            addUser(userId: $userId, userDetails: $userDetails) {
                userId
                name
            }`,
        variables: {
            userId: 'userId',
            userDetails: { name: 'name' },
        },
      };
    
      const uri = await URL.parse(endPoint);
    
      const options = {
        method: 'POST',
        body: JSON.stringify(postBody),
        headers: {
          host: uri.host,
          'Content-Type': 'application/json',
          Authorization: accessToken,
        },
      };
      const response = await fetch(uri.href, options);
      const { data } = await response.json();
    
      const result = data && data.addUser;
      callback(null, result);
    };
    

    确保您的 Cognito 用户池具有 USER_PASSWORD_AUTH 身份验证流程。

    【讨论】:

    【解决方案2】:

    AWS AppSync 支持通过 IAM 和 Cognito 用户池进行授权。它们可能会造成混淆,根据我的经验,AWS 文档和框架对这种混淆没有帮助。

    IAM 身份验证是所有主要 AWS 端点使用的。您可以使用正确的 IAM 身份验证和权限创建 DynamoDB 表。 IAM 请求是通过使用您的密钥对某些主机、路径、参数和标头进行签名(通常由 SDK 或 boto)发出的,并将其转换为签名。您的 Authorization 标头以 AWS4-HMAC-SHA256 开头,因此看起来您使用带有 v4 签名的 IAM 授权。

    Cognito 用户池身份验证使用 JWT 令牌进行授权。使用 Cognito 服务器进行身份验证后,您将获得访问令牌和身份令牌,它们可用于调用 AWS Appsync 等资源。 如果您将 Cognito 用户池与 Cognito 身份池连接,则使用这些访问令牌可以检索 IAM 令牌。如果您这样做,您可以使用这些令牌对 IAM 身份验证请求进行签名。

    您似乎为 AWS AppSync API 配置了 Cognito 用户池身份验证,但您正在使用 IAM 身份验证调用它。您可以使用 JWT 身份验证开始调用它,也可以将 AWS AppSync API 切换为使用 IAM 身份验证。您选择哪种身份验证方法会影响您如何实施细粒度访问控制(在 IAM 策略中与在您的 GraphQL 模式中)。在docs 中了解更多信息。

    【讨论】:

    • 感谢@bram 的回复。由于我的 appsync API 被移动客户端使用并且已经运行了一段时间,所以现在回到 IAM 不是一个可行的选择。我希望的是获得一个临时令牌,并传递这个 JWT 令牌。如果我查看凭证 param.WebIdentityToken,我可以在下面看到类似 JWT 令牌的东西,但这不会用于签名。
    • Cognito 用户池身份验证通过在 Authorization 标头中传递 JWT 令牌来工作。 JWT 令牌不能也不应该用于签署请求。 Cognito 用户池身份验证依赖于其他安全机制 (https) 来确保请求未被篡改。
    猜你喜欢
    • 2020-09-03
    • 2021-05-05
    • 2020-09-30
    • 2020-05-23
    • 2019-02-13
    • 2018-10-21
    • 2018-10-02
    • 2019-07-27
    • 2021-01-22
    相关资源
    最近更新 更多