手动签署 AppSync URL 以在 Lambda 中使用会产生错误的签名错误

Manually sign AppSync URL to use in Lambda gives bad signature error

在 Lambda 中,我想用 aws-signature-v4 签署我的 AppSync 端点,以便将其用于突变。

生成的 URL 似乎没问题,但是当我尝试它时它给了我以下错误:

{ "errors" : [ { "errorType" : "InvalidSignatureException", "message" : "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details. etc... } ] }

这是我的 lambda 函数

import { Context, Callback } from 'aws-lambda';
import { GraphQLClient } from 'graphql-request';

const v4 = require('aws-signature-v4');

export async function handle(event: any, context: Context, callback: Callback) {
  context.callbackWaitsForEmptyEventLoop = false;

  const url = v4.createPresignedURL(
    'POST',
    'xxxxxxxxxxxxxxxxx.appsync-api.eu-west-1.amazonaws.com',
    '/graphql',
    'appsync',
    'UNSIGNED-PAYLOAD',
    {
      key: 'yyyyyyyyyyyyyyyyyyyy',
      secret: 'zzzzzzzzzzzzzzzzzzzzz',
      region: 'eu-west-1'
    }
  );

  const mutation = `{
    FAKEviewProduct(title: "Inception") {
      productId
    }
  }`;

  const client = new GraphQLClient(url, {
    headers: {
      'Content-Type': 'application/graphql',
      action: 'GetDataSource',
      version: '2017-07-25'
    }
  });

  try {
    await client.request(mutation, { productId: 'jfsjfksldjfsdkjfsl' });
  } catch (err) {
    console.log(err);
    callback(Error());
  }

  callback(null, {});
}

我通过创建新用户和 Allowingappsync:GraphQL 操作获得了我的 keysecret

我做错了什么?

您无需构建预签名 URL 即可调用 AWS AppSync 端点。将 AppSync 端点上的身份验证模式设置为 AWS_IAM,向 Lambda execution role, and then follow the steps in the "Building a JavaScript Client" 教程授予调用变更或查询的权限。

这就是我通过使用 axios.

发出简单的 HTTP 请求来触发 AppSync 突变的方式
const AWS = require('aws-sdk');
const axios = require('axios');

exports.handler = async (event) => {    
    let result.data = await updateDb(event);

    return result.data;
};

function updateDb({ owner, thingName, key }){
    let req = new AWS.HttpRequest('https://xxxxxxxxxxx.appsync-api.eu-central-1.amazonaws.com/graphql', 'eu-central-1');
    req.method = 'POST';
    req.headers.host = 'xxxxxxxxxxx.appsync-api.eu-central-1.amazonaws.com';
    req.headers['Content-Type'] = 'multipart/form-data';
    req.body = JSON.stringify({
        "query":"mutation ($input: UpdateUsersCamsInput!) { updateUsersCams(input: $input){ latestImage uid name } }",
        "variables": {
            "input": {
                "uid": owner,
                "name": thingName,
                "latestImage": key
            }
        }
    });

    let signer = new AWS.Signers.V4(req, 'appsync', true);
    signer.addAuthorization(AWS.config.credentials, AWS.util.date.getDate());

    return axios({
        method: 'post',
        url: 'https://xxxxxxxxxxx.appsync-api.eu-central-1.amazonaws.com/graphql',
        data: req.body,
        headers: req.headers
    });
}

确保为您的 Lambda 函数赋予 IAM 角色 运行 作为 appsync:GraphQL.

的权限

在此处添加一个答案,因为我很难获得已接受的答案,而且我在 AWS SDK GitHub issues that said it's not recommended to use the AWS.Signers.V4 object in production. This is how I got it to work using the popular aws4 npm 模块上发现了一个问题,稍后在上面链接的问题中推荐了这个问题。

const axios = require('axios');
const aws4 = require('aws4');

const query = `
    query Query {
      todos {
        id,
        title
      }
    }`

const sigOptions = {
        method: 'POST',
        host: 'xxxxxxxxxx.appsync-api.eu-west.amazonaws.com',
        region: 'eu-west-1',
        path: 'graphql',
        body: JSON.stringify({
            query
        }),
        service: 'appsync'
    };

const creds = {
    // AWS access tokens
}

axios({
        url: 'https://xxxxxxxxxx.appsync-api.eu-west/graphql',
        method: 'post',
        headers: aws4.sign(sigOptions, creds).headers,
        data: {
            query
        }
    }).then(res => res.data))