Java Lambda で API Gateway の Lambda Authorizer を実装する


API Gateway(Rest API) の Lambda Authorizer では、Lambda のレスポンスに 指定の JSON を返す 必要があります。

Lambda Authorizer って何?って方は こちら を。

Node.js だと、こんな感じで、そのまま JSON を返せます。便利ですね。

exports.handler = async (event) => {
  console.log(JSON.stringify(event, null, 4));
  return {
    "principalId": "1234",
    "policyDocument": {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Action": "execute-api:Invoke",
          "Effect": "Allow",
          "Resource": event.methodArn
        }
      ]
    }
  };
};

Java の場合は、JSON では返せないですし、JSON を文字列として返してもうまくいきません。
方法としては 2 つあって、Map を使う方法と POJO クラスを使う方法です。

Map を使う方法

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class MapLambdaAuthorizer implements RequestHandler<Map<String, Object>, Map<String, Object>> {
    @Override
    public Map<String, Object> handleRequest(Map<String, Object> event, Context lambdaContext) {
        Map<String, Object> response = new HashMap<String, Object>();
        response.put("principalId", "1234");

        Map<String, Object> policyDocument = new HashMap<String, Object>();
        policyDocument.put("Version", "2012-10-17");

        Map<String, String> statement = new HashMap<>();
        statement.put("Action", "execute-api:Invoke");
        statement.put("Effect", "Allow");
        statement.put("Resource", (String) event.get("methodArn"));
        policyDocument.put("Statement", Arrays.asList(statement));

        response.put("policyDocument", policyDocument);

        Map<String, String> context = new HashMap<String, String>();
        context.put("now", new Date().toString());
        response.put("context", context);

        return response;
    }
}

POJO を使う方法

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class PojoLambdaAuthorizer implements RequestHandler<Map<String, Object>, AuthorizerResponse> {
    @Override
    public AuthorizerResponse handleRequest(Map<String, Object> event, Context lambdaContext) {
        AuthorizerResponse response = new AuthorizerResponse();
        response.setPrincipalId("1234");

        Map<String, Object> policyDocument = new HashMap<>();
        policyDocument.put("Version", "2012-10-17");

        Map<String, String> statement = new HashMap<>();
        statement.put("Action", "execute-api:Invoke");
        statement.put("Effect", "Allow");
        statement.put("Resource", (String) event.get("methodArn"));
        policyDocument.put("Statement", Arrays.asList(statement));

        response.setPolicyDocument(policyDocument);

        Map<String, String> context = new HashMap<>();
        context.put("now", new Date().toString());
        response.setContext(context);

        return response;
    }
}

import java.util.Map;

public class AuthorizerResponse {
    private String principalId;

    public void setPrincipalId(String principalId) {
        this.principalId = principalId;
    }

    public String getPrincipalId() {
        return this.principalId;
    }

    private Map<String, Object> policyDocument;

    public void setPolicyDocument(Map<String, Object> policyDocument) {
        this.policyDocument = policyDocument;
    }

    public Map<String, Object> getPolicyDocument() {
        return this.policyDocument;
    }

    private Map<String, String> context;

    public Map<String, String> getContext() {
        return context;
    }

    public void setContext(Map<String, String> context) {
        this.context = context;
    }
}

POJO にするなら、

policyDocument.put("Version", "2012-10-17");
statement.put("Action", "execute-api:Invoke");

とかも POJO にしないと気持ち悪いところですが、POJO にした場合に API Gateway に返される JSON のキー名が小文字始まり(version、action)になってしまい、うまく解釈してくれませんでした。

まとめ

JSON がそんなに大きくないので、Map 方式の方が読みやすくていいと思います。

Source Code