Giter Site home page Giter Site logo

go-cognito-lambda's Introduction

go-cognito-lambda

ci-master cd-master Coverage Status

CognitoUserPoolをトリガーとしたLambdaのサンプル色々

Getting Started

環境変数の設定

以下の環境変数を設定して下さい。

direnv/direnv 等を利用するのがオススメです。

export DEPLOY_STAGE=デプロイターゲット(.eg. dev, stg, prod)
export TARGET_USER_POOL_ID=ターゲットとなるUserPoolのID
export TRIGGER_USER_POOL_NAME=ターゲットとなるUserPoolの名前
export REGION=AWSのリージョン(.eg. ap-northeast-1)
export API_DOMAIN_NAME=API Gatewayに設定するドメイン名を指定、予めRoute53にホストゾーンが設定されている必要があります
export CERTIFICATE_ARN=AWS Certificate ManagerのARNを指定、 "*.ドメイン名" で指定した証明書は利用出来ないので注意
export NEXT_IDAAS_SERVER_CLIENT_ID=クライアントシークレットを安全に保管出来るサーバーサイドアプリケーション用のUserPoolClientIDを指定
export DYNAMODB_TEST_ENDPOINT=テスト用のDynamoDBのエンドポイントを指定、ローカルで実行する時は http://localhost:58000 を指定

AWSクレデンシャルの設定

従って以下のように 名前付きプロファイル を作成して下さい。

~/.aws/credentials

[nekochans-dev]
aws_access_key_id=YOUR_AWS_ACCESS_KEY_ID
aws_secret_access_key=YOUR_AWS_SECRET_ACCESS_KEY

無論このプロファイル名は好きな名前に変えてもらって問題ありません。

その場合は serverless.yml 内の custom.profiles を全て修正して下さい。

Goのインストール

go1.15 をインストールします。

Node.jsのインストール

最新安定版をインストールします。

npm packageのインストール

npm ci を実行してpackageをインストールします。

Dockerで必要なコンテナを生成する

docker-compose up -d で必要なコンテナを起動して下さい。

ソースコードのフォーマットやDynamoDBを使ったテストはDocker上でないと正常動作しません。

デプロイ関連のコマンド

Build & Deploy

make deploy を実行すると build , deploy が実行されます。

deployは Serverless Framework を利用しています。

このツールを利用すると、既存のCognitoUserPoolに対してLambda関数をアタッチ出来るので、その機能を利用する事が主な目的です。

それ以外にも公式の AWS SAM と比較して痒いところに手が届くので、その点も良いと思います。

deployしたリソースを削除する

make remove を実行します。

その他のコマンド

テスト実行

Goのコンテナ内で make test を実行します。

docker-compose exec go make test でも大丈夫です。

ソースコードのformat

Goのコンテナ内で make format を実行します。

docker-compose exec go make format でも大丈夫です。

Lintの実行

make format では修正出来ないエラー内容を表示します。

Goのコンテナ内で make lint を実行します。

docker-compose exec go make lint でも大丈夫です。

開発を行う為の参考資料

Cognitoをカスタマイズする為のLambdaは以下の種類が存在します。

  • カスタム認証フロー
  • 認証イベント
  • サインアップ
  • メッセージ
  • トークンの作成

詳しくは こちら を見て下さい。

また serverless.yml にトリガーにCognitoのイベントを設定する必要があります。

それに関しては下記のドキュメントが参考になります。

APIの認証・認可について

本リポジトリで実装されているAPIは CognitoUserPool が発行するJWTトークンによって保護されています。

serverless.ymlhttpApi.authorizers の設定次第ですが、ここでは Client Credentials Grant(RFC 6749) の仕組みでアクセストークンを発行する例を紹介します。

具体的な手順は下記の通りです。

Client Credentials Grant(RFC 6749) でのアクセストークン発行方法

1. アプリクライアントIDとアプリクライアントのシークレットを : で繋いでBase64Encodeした値を生成する

echo -n "【アプリクライアントID】:【アプリクライアントのシークレット】" | base64 で生成を行います。

仮に 【アプリクライアントID】が aaa, アプリクライアントのシークレットが bbb なら以下のようになります。

echo -n "aaa:bbb" | base64

# 実際にはもっと長い値が生成されます
YWFhOmJiYg==

2. 1で生成した値を使ってアクセストークンを発行する

以下のようにCognitoUserPoolのトークンエンドポイントに対してリクエストを行います。

curl -v \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Authorization: Basic {1で生成した値を指定する}" \
--data "grant_type=client_credentials" \
--data "scope={DEPLOY_STAGE}-cognito-admin-api.keitakn.de/admin" \
https://{CognitoUserPoolドメイン名}.auth.ap-northeast-1.amazoncognito.com/oauth2/token
  • grant_typeは client_credentials 固定です
  • scopeの {DEPLOY_STAGE} にはデプロイ時に利用している {DEPLOY_STAGE} の値を利用します。(-cognito-admin-api.keitakn.de/admin の部分は固定です)
  • CognitoUserPoolドメイン名 に関してはAWSコンソール上のCognitoUserPoolの「ドメイン名」からご確認下さい。

成功すると以下のようなリクエストが返ってきます。

{
  "access_token": "JWT形式のトークン",
  "expires_in": 3600,
  "token_type": "Bearer"
}

3. アクセストークンを用いて、APIにリクエストを行う

以下のように Authorization: Bearer + アクセストークン を指定してリクエストを行います。

curl -v \
-X PATCH \
-H "Content-type: application/json" \
-H "Authorization: Bearer {2で取得したアクセストークンを指定}" \
-d \
'
{
  "userName": "対象のcognitoUsernameを指定",
  "newPassword": "新しいパスワード"
}
' \
https://${API_DOMAIN_NAME}/users/passwords | jq

トークンが有効な間は正常に200系のレスポンスが返ってきます。

トークンが無効、もしくは有効期限切れの場合は以下のようなレスポンスが返ってきます。

< HTTP/2 401
< date: Thu, 22 Oct 2020 03:10:39 GMT
< content-length: 26
< www-authenticate: Bearer scope="dev-cognito-admin-api.keitakn.de/admin" error="invalid_token" error_description="the token has expired"
< apigw-requestid: xxxxxxx=
<
{ [26 bytes data]
100   128  100    26  100   102    106    418 --:--:-- --:--:-- --:--:--   524
* Connection #0 to host xxxxx.execute-api.ap-northeast-1.amazonaws.com left intact
* Closing connection 0

{
  "message": "Unauthorized"
}

コーディング規約

Goの標準的な慣例に従います。

  • ファイル名はスネークケース
  • ディレクトリ名は小文字のみ利用する形する
  • 構造体、変数名はキャメルケース
  • 引数、レシーバ名はなるべく1文字の単語を使用する
  • package名は小文字のみを利用する

1つ例外があります。

urlURL を使うとか、 apiAPI を使う等のルールは採用していません。

理由としては下記の通りです。

  • golangci-lint でこのルールをチェック出来るが、カバーされている単語が少ない
  • どれが略語なのかをその都度判断するのが難しい、人によっては出来たり出来なかったりするので、かえって統一感のないコードが出来上がってしまう可能性が高い

個人で書いた記事ですが こちら にさらに詳しい理由が書いてあります。

.go 以外のファイル名に関するルール

  • HTMLファイル(慣例に従いケバブケース)
  • go buildで生成したファイル(package名と同様にしたいので、小文字のみを利用)

go-cognito-lambda's People

Contributors

keitakn avatar

Stargazers

Shoma Okamoto avatar ken_o avatar

Watchers

James Cloos avatar  avatar

go-cognito-lambda's Issues

CIの実装を行う

完了の定義

  • PR作成時にテストとLintの実行が行われるようになっている事
  • テストやLintの差分があるPRはマージ出来ないようになっている事

CDの実装を行う

完了の定義

  • メインブランチにマージされた際にデプロイが行われるようになっている事

Cognitoのサインアップを完了させるAPIを実装する

完了の定義

  • サインアップを完了させる為のAPIが実装されている事

補足情報

aws-amplify を使えないケースもあるのでAPIとして実装する方法を把握しておく。

#46 で作成したAPI内で送信されるメッセージ内リンクからこのAPIが利用される。

Cognitoの識別子からCognitoユーザーを取得するAPIの実装

Doneの定義

  • 表題のAPIが実装されている事

補足情報

	mySession := session.Must(session.NewSessionWithOptions(session.Options{Profile: "default"}))
	svc := cognitoidentityprovider.New(mySession, aws.NewConfig().WithRegion("ap-northeast-1"))

	userPoolId := os.Getenv("TARGET_USER_POOL_ID")
	inputAdminGetUser := &cognitoidentityprovider.AdminGetUserInput{
		UserPoolId: &userPoolId,
		Username: &username,
	}

	user, err := svc.AdminGetUser(inputAdminGetUser)

これで問題ないハズだが NoCredentialProviders: no valid providers in chain. Deprecated. が発生してしまう。

このあたりも調査しながら実施する。

API Gateway v2で動作するAPIの実装

Doneの定義

  • API Gateway v2 で動作しているAPIが実装されている事(実装は仮でOK)
  • JWT AuthorizerによりAPIが保護されている事

補足情報

APIは管理者用の強力な権限を持ったAPIを想定。

故に認証・認可はCognitoのClient Credentials Grantで発行したアクセストークンを利用する。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.