0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

できるだけ最小構成のAWS AppSync with Lambda認証

Posted at

作りたいもの

CDKでつくるMutation, Query, Subscriptionをするだけのできるだけ小さいサンプル2
認証をLambdaでする

完成品 https://github.com/tky/app-sync-with-lambda-auth-example

注意点

  • subscription使うためにはschemaはcodeで定義
  • aws-cdk/aws-appsync-alphaは将来変更が入るかも

実装

importから

import { Duration, Stack, StackProps } from "aws-cdk-lib";
import { Construct } from "constructs";
import { Table, AttributeType } from "aws-cdk-lib/aws-dynamodb";
import {
  AuthorizationType,
  Directive,
  GraphqlApi,
  Field,
  GraphqlType,
  InputType,
  MappingTemplate,
  ObjectType,
  PrimaryKey,
  Values,
  ResolvableField,
  Schema,
} from "@aws-cdk/aws-appsync-alpha";
import { RemovalPolicy } from "aws-cdk-lib";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";

簡単なschema

    const typeUser = new ObjectType("User", {
      definition: {
        id: GraphqlType.string({ isRequired: true }),
        name: GraphqlType.string({ isRequired: true }),
        age: GraphqlType.int({ isRequired: false }),
      },
    });

    const typeUserInput = new InputType("UserInput", {
      definition: {
        name: GraphqlType.string({ isRequired: true }),
        age: GraphqlType.int({ isRequired: false }),
      },
    });

    const schema = new Schema();
    schema.addType(typeUser);
    schema.addType(typeUserInput);

認証用のlambda

NodejsFunctionはこの書き方だと、{stackのファイル名}.{NodejsFunctionのid}.tsというファイルを探しに行きます。
cdk-stack.tsでhandlerというidにしたのでこのcdk-stack.tsと同じディレクトリにあるcdk-stack.handler.tsが必要です。
id変えたりstackのファイル名を変更する場合は注意が必要

    const handler = new NodejsFunction(this, "handler", {
      functionName: "app-sync-with-lambda-auth-hander",
    });

API。認証をLambaにする

    const api = new GraphqlApi(this, "api", {
      name: "app-sync-with-lambda-auth-example-api",
      schema,
      authorizationConfig: {
        defaultAuthorization: {
          authorizationType: AuthorizationType.LAMBDA,
          lambdaAuthorizerConfig: {
            handler,
            resultsCacheTtl: Duration.seconds(1),
          },
        },
      },
      xrayEnabled: false,
    });

dynamodb

    const table = new Table(this, "table", {
      tableName: "app-sync-with-lambda-auth-example-table",
      partitionKey: {
        name: "id",
        type: AttributeType.STRING,
      },
      removalPolicy: RemovalPolicy.DESTROY,
    });

    const dataSource = api.addDynamoDbDataSource("data_source", table);

Query

    schema.addQuery(
      "getUser",
      new ResolvableField({
        returnType: typeUser.attribute(),
        args: {
          id: GraphqlType.id({ isRequired: true }),
        },
        dataSource,
        requestMappingTemplate: MappingTemplate.dynamoDbGetItem("id", "id"),
        responseMappingTemplate: MappingTemplate.dynamoDbResultItem(),
      })
    );

Mutation

    schema.addMutation(
      "addUser",
      new ResolvableField({
        returnType: typeUser.attribute(),
        args: {
          id: GraphqlType.string({ isRequired: true }),
          input: typeUserInput.attribute({ isRequired: true }),
        },
        dataSource,
        requestMappingTemplate: MappingTemplate.dynamoDbPutItem(
          PrimaryKey.partition("id").is("id"),
          Values.projecting("input")
        ),
        responseMappingTemplate: MappingTemplate.dynamoDbResultItem(),
      })
    );

Subscription

    schema.addSubscription(
      "updatedUser",
      new Field({
        returnType: typeUser.attribute(),
        args: { id: GraphqlType.id({ isRequired: true }) },
        directives: [Directive.subscribe("addUser")],
      })
    );

実行

API認証の場合は-H "x-api-key:${API_KEY}"が必要でしたが今回はlambda認証なので代わりに-H "Authorization:${KEY}"が必要です

とりあえずABCにしてあります

export QUERY='
  mutation AddUser {
    addUser(id: "user1", input: {age: 22, name: "first user"}) {
      age
      id
      name
    }
  }
'
gq ${API_ENDPOINT} -H "Authorization:ABC" -q "${QUERY}"
Executing query... done
{
  "data": {
    "addUser": {
      "age": 22,
      "id": "user1",
      "name": "first user"
    }
  }
}

もちろん他の値だと認証失敗

$ gq ${API_ENDPOINT} -H "Authorization:XYZ" -q "${QUERY}"
Executing query... error
Error:  {
  errors: [
    {
      errorType: 'UnauthorizedException',
      message: 'You are not authorized to make this call.'
    }
  ]
}

lambda

lib/cdk-stack.hander.ts
exports.handler = async (event: any) => {
  console.log(JSON.stringify(event));

  const isAuthorized = event.authorizationToken == "ABC";

  const response = {
    isAuthorized,
  };

  console.log(JSON.stringify(response));
  return response;
};

hotswapつけてwatchするとlambda変更してすぐデプロイしてくれて便利です。
ついでにconsoleにログも出してくれます。

$cdk watch --hotswap
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?