やりたいこと
フロントエンド(ここではReactアプリ)から、APIGateway経由でLambda関数を実行するときにCognitoで認証されたユーザーからのリクエストのみをAPIGatewayで受け付けるようにしたい
※備忘録に近い内容です
作成手順
①Lambda関数を作成
何でも良いのでLambda関数を作成
とりあえず作成したときに出来上がるHelloLambdaのままとした
(ここでやりたいことはLambdaの中身は関係ないので)
export const handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
②APIGateway作成
・HTTP APIを作成
・Authorization設定
オーソライザーのタイプ:JWT
IDソース:$request.header.Authorization
発行者URL:https://cognito-idp.ap-northeast-1.amazonaws.com/{userPoolId}
対象者:CognitoユーザープールのアプリケーションクライアントIDを入力
・CORSの設定(ReactアプリからAPIGatewayを呼び出すため)
Access-Control-Allow-Origin:* (本番環境の場合は具体的なドメイン名を指定すること)
Access-Control-Allow-Methods:*
Access-Control-Allow-Headers:content-type,authorization
試しに実行
ブラウザからAPIGatewayのURLをたたいてみる
-> 401 Unauthorizedが返ってくる。想定通り
ReactからAPIGateway実行
import {
CognitoUserPool,
AuthenticationDetails,
CognitoUser,
} from "amazon-cognito-identity-js";
const poolData = {
UserPoolId: "ap-northeast-1_xxxxxxxxx", // ユーザープールID
ClientId: "6b093xxxxxxxxxxxxxxxxxxxx", // アプリクライアントID
};
const userPool = new CognitoUserPool(poolData);
// Cognitoログイン
function signIn(username, password) {
const authenticationData = {
Username: username,
Password: password,
};
const authenticationDetails = new AuthenticationDetails(authenticationData);
const userData = {
Username: username,
Pool: userPool,
};
const cognitoUser = new CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: (result) => {
debugger;
const accessToken = result.getAccessToken().getJwtToken();
const idToken = result.getIdToken().getJwtToken();
console.log("access token: " + accessToken);
console.log("id token: " + idToken);
// アクセストークンを使用した処理をここに記述
alert("ログイン完了" + accessToken);
},
onFailure: (err) => {
console.error(err);
alert(err.message || JSON.stringify(err));
},
});
}
// APIGateway Called
const apiGatewayCall = async (idToken) => {
debugger;
try {
const response = await fetch(
"https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/endpoint",
{
method: "GET",
headers: {
Authorization: `Bearer ${idToken}`,
"Content-Type": "application/json",
},
}
);
const result = await response.json();
console.log("result", result);
} catch (error) {
console.error("api error", error);
}
};
export default function LoginForm() {
const handleLogin = (event) => {
event.preventDefault();
const username = event.target.username.value;
const password = event.target.password.value;
signIn(username, password);
};
const apiCall = (event) => {
event.preventDefault();
const idToken = event.target.idToken.value;
apiGatewayCall(idToken);
};
return (
<>
<form onSubmit={handleLogin}>
<input type="text" name="username" required />
<input type="password" name="password" required />
<button type="submit">ログイン</button>
</form>
<br />
<form onSubmit={apiCall}>
id_token=
<input type="text" name="idToken" required />
<button type="submit">ApiCall</button>
</form>
</>
);
}
使い方
①一つ目のformのインプットテキストにCognitoユーザーIDとパスワードを入力してログインボタン押下
②signIn関数が実行されるので、console.logで取得しているaccess tokenまたはid tokenをメモ
③ ②でメモしたtoken(access tokenを使う場合が多い)を二つ目のformのインプットテキストに入力しApiCallボタン押下
④apiGatewayCall関数が実行される。
正しく実行されていれば、result.messageに「Hello from Lambda!」200が返ってくる
認証エラーの場合、result.messageに「Unauthorized」401が返ってくる