简体   繁体   中英

How to authorize with AWS signature 4 -> API Gateway -> Lambda

I've googled around a lot with no luck in finding the solution to my problem. I've read through the entire authentication process for AWS Signature 4 and followed their tutorial as well as view other sources. I'm trying to have client side authentication for a desktop application that makes request to API Gateway.

When I use Postman it works properly but I tried generating my own signature in Nodejs but to no avail, I keep getting 403 messages back from the call.

The function below returns the authenticated requestUrl which is then run by axios.get(requestUrl). When I use the Postman generated request it works perfectly fine but, once I use my generated request I have problems. Am I missing something while authenticating? Here is what my code currently looks like:

function Authorize() {
  const host = "EXAMPLE.execute-api.us-east-1.amazonaws.com"
  const reg = 'us-east-1'
  const meth = 'GET'
  const serv = 'execute-api'
  const endpoint = '/development/putImage'
  // Keys
  let access = "EXAMPLE"
  let key = "KEY"
  
  // Get Date
  let t = new Date();
  let amzDate = t.toJSON().replace(/[-:]/g, "").replace(/\.[0-9]*/, "");
  let dateStamp = t.toJSON().replace(/-/g, "").replace(/T.*/, "");

  // ************* TASK 1: CREATE CANONICAL REQUEST *************
  // Create Canonical Request
  let canonical_uri=endpoint
  let canonical_headers="host: "+host+"\n"

  let signedHeaders = 'host'
    
  let algorithm = 'AWS4-HMAC-SHA256'
  let credentialScope = dateStamp + "/" + reg + "/" + serv + "/" + "aws4_request"

  // Set query string
  let canonicalQueryString = ""
  canonicalQueryString += "X-Amz-Date=" + amzDate
  canonicalQueryString += "&X-Amz-Algorithm=" + algorithm;
  canonicalQueryString += "&X-Amz-Credential=" + encodeURIComponent(access + "/" + credentialScope)
  canonicalQueryString += "&X-Amz-SignedHeaders=" + signedHeaders
  
  // Empty payload for get request
  var payloadHash = crypto.createHash('sha256').update('').digest('hex');
  
  // Set canonical request
  var canonicalRequest = meth + "\n" + canonical_uri + "\n" + canonicalQueryString + "\n" + canonical_headers + "\n" + signedHeaders + "\n" + payloadHash
  console.log(canonicalRequest)

  // ************* TASK 2: CREATE THE STRING TO SIGN*************
  let stringToSign = algorithm + '\n' + amzDate + '\n' + credentialScope + '\n' + crypto.createHash('sha256').update(canonicalRequest).digest('hex');

  // ************* TASK 3: CALCULATE THE SIGNATURE *************
  var signingKey = getSignatureKey(key, dateStamp, reg, serv)
  var signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest('hex');
  
  // ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
  canonicalQueryString += '&X-Amz-Signature=' + signature
  let requestUrl = "https://"+host+ endpoint + "?" + canonicalQueryString
 
  console.log(requestUrl)
  
  return requestUrl
}

The below code worked for me well. For more info, please visit https://docs.aws.amazon.com/opensearch-service/latest/developerguide/request-signing.html#request-signing-node

const { HttpRequest} = require("@aws-sdk/protocol-http");
const { defaultProvider } = require("@aws-sdk/credential-provider-node");
const { SignatureV4 } = require("@aws-sdk/signature-v4");
const { NodeHttpHandler } = require("@aws-sdk/node-http-handler");
const { Sha256 } = require("@aws-crypto/sha256-browser");

...

var request = new HttpRequest({
        body: JSON.stringify({"users":["G0000000B","G0000000A"]}),
        headers: {
            'Content-Type': 'application/json',
            'apiKey':'XXXXXXXXXXXX',
            'apiSecret': 'XXXXXXXXXXXXXXXXXX',
            'host': 'service2.xxx.xxx.xx'
        },
        hostname: 'service2.xxx.xxx.xx',
        method: 'POST',
        path: 'API/user/list'
    });
    
    var signer = new SignatureV4({
        credentials: defaultProvider(),
        region: 'ap-southeast-1',
        service: 'execute-api',
        sha256: Sha256
    });

    const signedRequest = await signer.sign(request);
    
    // Send the request
    var client = new NodeHttpHandler();
    var { response } =  await client.handle(signedRequest)
    console.log(response.statusCode + ' ' + response.body.statusMessage);
    var responseBody = '';
    await new Promise(() => {
      response.body.on('data', (chunk) => {
        responseBody += chunk;
      });
      response.body.on('end', () => {
        console.log('Response body: ' + responseBody);
      });
    }).catch((error) => {
        console.log('Error: ' + error);
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM