CDKでGraphQLに挑戦する(認証編)


はじめに

本日はGWアドベントカレンダー3日目です。昨日で簡単なGraphQLサーバーの実装ができたので今日はそれにCognitoを追加して認証機能を実装していきます。

Cognitoとは

公式のドキュメントを拝借すると、Amazon Cognito を使用すれば、ウェブアプリケーションおよびモバイルアプリに素早く簡単にユーザーのサインアップ/サインインおよびアクセスコントロールの機能を追加できます。とのこと。
CogitoはフルマネージドのAWSサービスとなってます。一々こちらでデータベースやアプリケーションの実装をすることなくセキュアなユーザー管理システムを実現させることができます。AppSyncはCognitoとの連携が簡単に実現できるので、今回はAppSyncのクエリ操作を認証されたユーザーに限定していきたいと思います。

CDKを実装

Cognitoのユーザープール(ユーザー管理を行うところ)作成に関するコードは実は以下の1行だけで十分です。

const userPool = new UserPool(this, 'UserPool')

あとはこのユーザープールをAppSyncに連携させます。以下のコードが全体のコードになります。

import * as cdk from '@aws-cdk/core'
import { GraphQLApi, MappingTemplate, PrimaryKey, Values, UserPoolDefaultAction } from '@aws-cdk/aws-appsync'
import { Table, AttributeType } from '@aws-cdk/aws-dynamodb'
import { UserPool } from '@aws-cdk/aws-cognito'

export class CdkAppsyncTestStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

    const userPool = new UserPool(this, 'UserPool')

    const api = new GraphQLApi(this, 'graphQlApi', {
      name: 'test-api',
      authorizationConfig: {
        defaultAuthorization: {
          userPool,
          defaultAction: UserPoolDefaultAction.ALLOW,
        },
      },
      schemaDefinitionFile: './schema.graphql',
    })

    const itemTable = new Table(this, 'itemTable', {
      partitionKey: {
        name: 'id',
        type: AttributeType.STRING,
      }
    })

    const itemDS = api.addDynamoDbDataSource('Item', 'Item data source', itemTable)
    itemDS.createResolver({
      typeName: 'Query',
      fieldName: 'allItem',
      requestMappingTemplate: MappingTemplate.dynamoDbScanTable(),
      responseMappingTemplate: MappingTemplate.dynamoDbResultList(),
    })
    itemDS.createResolver({
      typeName: 'Mutation',
      fieldName: 'addItem',
      requestMappingTemplate: MappingTemplate.dynamoDbPutItem(
        PrimaryKey.partition('id').auto(),
        Values.projecting('item')),
      responseMappingTemplate: MappingTemplate.dynamoDbResultItem(),
    })
  }
}

CfnApiKey()は今回はCognitoのAPI Key認証を用いるので不要です。GraphQLApi()のpropsにauthorizationConfigというフィールドが追加されました。
これだけでCognitoとの連携は可能です。

実行する

早速認証の機能がちゃんと動くのか試してみたいと思います。CognitoユーザーのログインはAppSyncのクエリ実行ページから行えます。事前にCognitoのユーザープールにユーザーを作成する必要があります。

ログインなし(認証トークンなし)の状態だと以下のメッセージが返ってくるかと思います。

{
  "errors": [
    {
      "errorType": "UnauthorizedException",
      "message": "Unable to parse JWT token."
    }
  ]
}

しかしユーザープールでログインというボタンを押してログインを行うと今まで通りのGraphQLのクエリ実行が行えるかと思います。

一応赤枠で示しているのが、ufoo68というユーザー名でログインしたという部分です。この状態になってはじめてクエリの実行に成功することができます。

さいごに

今日までの内容で公式のサンプルコードの概要がある程度わかるようになりました。まだ日はあるのでもう少しAppSyncと戯れてみようかと思います。ではまた明日!