使用 Cognito 用户池从 Lambda 调用 APPSYNC 突变 - UnauthorizedException

Som*_*uru 1 lambda amazon-cognito aws-appsync

我正在尝试调用 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)
});
Run Code Online (Sandbox Code Playgroud)

现在,我打电话

 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);
        });
});
Run Code Online (Sandbox Code Playgroud)

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

 {
     "Effect": "Allow",
      "Principal": {
        "Federated": "cognito-identity.amazonaws.com"
       },
        "Action": "sts:AssumeRoleWithWebIdentity"
    }
Run Code Online (Sandbox Code Playgroud)

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

当我查看生成的标头时,我没有看到 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' }
Run Code Online (Sandbox Code Playgroud)

提前致谢

Bra*_*ram 5

AWS AppSync 支持通过 IAM 和 Cognito 用户池进行授权。它们可能会令人困惑,根据我的经验,AWS 文档和框架无助于解决这种困惑。

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

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

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


小智 5

你可以试试这个:

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);
};
Run Code Online (Sandbox Code Playgroud)

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