はじめに
ログイン機能のあるWEBサービスで利用されるAPIで、APIに認可を設定しなかった場合、APIのURLさえわかれば、どのユーザでもAPIが実行できてしまいます。
そのため、ログインユーザのみ許可されるAPIを作成する場合、適切な認可を設計する必要があります。
今回はAWS Cognitoでログインしているユーザのみ、APIGatewayで作成されたAPIが許可される設定をご紹介します。
※Cognitoは構築されている前提です。Cognitoの構築については以下の記事をご覧ください。
https://qiita.com/haruya_hamasaki/items/b4257ec4498185fa38a1
https://qiita.com/haruya_hamasaki/items/92d5972e46768a902104
API Gateway の設定
構築に使用するSAMテンプレートの例です。
MyMovieAPIGateway:
Type: AWS::Serverless::Api
Properties:
AccessLogSetting:
DestinationArn: !GetAtt ApigwLogDeliveryStream.Arn
Format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "caller":"$context.identity.caller", "user":"$context.identity.user","requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","resourcePath":"$context.resourcePath", "status":"$context.status","protocol":"$context.protocol", "responseLength":"$context.responseLength" }\n'
StageName: api
ApiKeySourceType: HEADER
EndpointConfiguration:
Type: REGIONAL
DefinitionBody:
swagger: "2.0"
info:
description: "get userid"
version: "1.0"
title: "mymovie"
basePath: "/api"
schemes:
- "https"
paths:
/movie:
delete:
consumes:
- "application/json"
produces:
- "application/json"
parameters:
- name: "user_id"
in: "query"
required: false
type: "string"
- name: "title"
in: "query"
required: false
type: "string"
responses:
"200":
description: "200 response"
schema:
$ref: "#/definitions/Empty"
"400":
description: "400 response"
"500":
description: "500 response"
security:
- MyMovie: []
- api_key: []
x-amazon-apigateway-integration:
httpMethod: "POST"
uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${DelMovFunction.Arn}/invocations"
responses:
default:
statusCode: "200"
".*\"statusCode\": 500,.*":
statusCode: "500"
".*\"statusCode\": 400,.*":
statusCode: "400"
requestTemplates:
application/json: "{\n \"user_id\": \"$input.params('user_id')\",\n \"\
title\": \"$input.params('title')\"\n}"
passthroughBehavior: "when_no_templates"
contentHandling: "CONVERT_TO_TEXT"
type: "aws"
securityDefinitions:
api_key:
type: "apiKey"
name: "x-api-key"
in: "header"
MyMovie:
type: "apiKey"
name: "Authorization"
in: "header"
x-amazon-apigateway-authtype: "cognito_user_pools"
x-amazon-apigateway-authorizer:
providerARNs:
- !GetAtt MyMovieUserPool.Arn
type: "cognito_user_pools"
上記だと余計な記載があり過ぎるので、認可の部分を抜粋します。
以下で、MyMovieと命名したオーソライザーを定義。
MyMovie:
type: "apiKey"
name: "Authorization"
in: "header"
x-amazon-apigateway-authtype: "cognito_user_pools"
x-amazon-apigateway-authorizer:
providerARNs:
- !GetAtt MyMovieUserPool.Arn
type: "cognito_user_pools"
以下で、オーソライザーを認可に設定しています。
security:
- MyMovie: []
この設定で、APIのリクエストヘッダーにCognitoから付与されたトークンがないと、APIの実行が許可されない設定となりました。
JavaScript
今回はAPIをJavaScriptから実行します。
まず、ログインしているCognito UserPoolを指定し、情報を変数に格納します。
// ユーザープールの設定
var user_pool_id = "{USER_POOL_ID}"
var client_id = "{CLIENT_ID}"
const poolData = {
UserPoolId : user_pool_id,
ClientId : client_id
};
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
const cognitoUser = userPool.getCurrentUser();
ログインユーザ情報から、トークンを抜き出します。
cognitoUser.getSession(function(err, session) {
id_token = session["idToken"]["jwtToken"]
});
ヘッダーにトークンを入れて、APIを実行します。
ログインユーザであれば、トークンが取得できているはずなので、APIが成功します。
逆にログインユーザ以外は失敗します。
fetch(`https://{DOMAIN}/api/movie?user_id=${user_id}&title=${title}`,{
//ヘッダーにトークンを入れる
headers: {
Authorization: id_token
},
//HTTPメソッド
method: "delete"
})
.then(response => {
if (!response.ok) {
//失敗時の処理
} else {
//成功時の処理
}
})
.catch(error => {
//失敗時の処理
});
おまけ
本記事の機能は以下のサービスで利用されています。
気になった方は、お気軽にサービスも利用くださると大変嬉しいです。
GitHubには、今回紹介したコードが実際に使われている形であります。
観た映画を登録、管理できるサービス MyMovie
サービスURL : mymovie.jp
GitHub(アプリ) : github.com/hamasakiharuya/mymovie
GitHub(CloudFormation/SAM) : github.com/hamasakiharuya/sam-mymovie