目的
APIの処理をAPIを叩いてきたユーザー名によって変えたいということがありました。
そこで、Cognitoでオーソライズを行っているLambda関数にて、API Gatewayの認証情報をLambda(Golang)の中で取得する方法を調べました。
結論
以下のコードでユーザー名を取得できます。
func handler(ctx context.Context, apiGWEvent events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
ユーザー名取得
diaryGetter := apiGWEvent.RequestContext.Authorizer["claims"].(map[string]interface{})["cognito:username"].(string)
/// ...略
}
割と途中のコードとかが謎ですので、以下に解説を載せておきます。(これより単純に取得できる方法がありましたらご教授いただけると幸いです。)
解説
(前提として、LambdaのオーソライザーにCognitoのユーザープールが設定されていることを確認)
まず、events.APIGatewayProxyRequestにはどのようなhttpリクエストを受け取ったのかが格納されます。
ドキュメントを参照すると、
type APIGatewayProxyRequest struct {
Resource string `json:"resource"` // The resource path defined in API Gateway
Path string `json:"path"` // The url path for the caller
HTTPMethod string `json:"httpMethod"`
Headers map[string]string `json:"headers"`
MultiValueHeaders map[string][]string `json:"multiValueHeaders"`
QueryStringParameters map[string]string `json:"queryStringParameters"`
MultiValueQueryStringParameters map[string][]string `json:"multiValueQueryStringParameters"`
PathParameters map[string]string `json:"pathParameters"`
StageVariables map[string]string `json:"stageVariables"`
RequestContext APIGatewayProxyRequestContext `json:"requestContext"`
Body string `json:"body"`
IsBase64Encoded bool `json:"isBase64Encoded,omitempty"`
}
となっております。
参考:GoDoc package aws/aws-lambda-go/events
参考:AWS Lambda+API Gateway+DynamoDBでCRUD APIを作るのをGolangでやってみた
こちらの、RequestContext構造体には、Authorizer情報がmap[string]interface{}
型で入っています。
僕が作成したアプリのdev環境用のCognitoの情報を取得してみると、以下の様になっています。
map[claims:map[aud:tekitoutekitou auth_time:12345678 cognito:username:テスト太郎 event_id:tekitou-d37c-41c9-be67-tekitou exp:Tue May 11 14:18:46 UTC 2021 iat:Tue May 11 13:18:46 UTC 2021 iss:https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-tekitou sub:tekitou-c7e9-4649-ab16-tekitou token_use:id]]
こちらから、claimsキーの中の、cognito:usernameキーがユーザーネームであることがわかります。
最初この構造を見たとき、
diaryGetter := apiGWEvent.RequestContext.Authorizer["claims"]["cognito:username"]
みたいな感じでとれるんじゃないの?
と思ったのですが、これをやろうとすると、
invalid operation: cannot index apiGWEvent.RequestContext.Authorizer["claims"] (map index expression of type interface{})
となってしまいます。
interface型の知識が欠如しておりました。
どんな型の値でも受け取れるinterface{}ですが、interface{}型の引数で受け渡された値は、元の型の情報が欠落しています。
(元の型の値を操作するための関数等を実行できません)
引用:https://blog.y-yuki.net/entry/2017/05/08/000000
元の型の値を操作できないため、辞書型のキーを取り出すという動作ができないっぽいです。
なので、型アサーションをして、取り出す必要がありました。さらにこのdiaryGetter
はstring型として扱いたいので、最後も型アサーションをする必要があったということです。
まず、
apiGWEvent.RequestContext.Authorizer["claims"]
を型アサーションでmap[string]interface{}
型にして、mapのキーを取り出すという感じです。