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

时间:2018-12-13 09:45:29

标签: 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)
});

现在,我打电话

 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”,             “ message”:“无法解析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' }

预先感谢

2 个答案:

答案 0 :(得分:3)

AWS AppSync支持通过IAM和Cognito用户池进行授权。它们可能会造成混淆,并且以我的经验,AWS文档和框架无法解决这种混乱。

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

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

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

答案 1 :(得分:2)

您可以尝试以下方法:

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身份验证流。