はじめに
こんにちは、梅雨です。
今回は、Next.js Middleware で Cognito ユーザの所属するグループによって認可処理を行う方法について解説していこうと思います。
AWS Amplify とは?
AWS Amplify は、フロントエンドとクラウドバックエンドを効率に構築・デプロイするためのフレームワークです。
Amplify を使うことで、認証、DB、API などのバックエンド機能を簡単にセットアップでき、フロントエンドとシームレスに統合することができます。
認証機能に関しては、Amazon Cognito と統合することでユーザのサインインやサインアップを短時間で実装できます。
実装
早速実装に移っていきましょう。
ランナーの準備
まずは createServerRunner
関数でサーバランナーを用意します。
この関数は @aws-amplify/adapter-nextjs
パッケージから提供されています。
npm i @aws-amplify/adapter-nextjs
import config from "src/aws-exports";
import { createServerRunner } from "@aws-amplify/adapter-nextjs";
const { runWithAmplifyServerContext } = createServerRunner({
config,
});
通常の認証
続いて、Cognito ユーザの通常の認証を行なっていきます。
さきほど作成したランナー内で fetchAuthSession
関数を用いてユーザセッションを取得し、セッションが存在しないまたはセッショントークンが存在しないときは強制的に /login
に飛ばすようにしています。
const middleware = async (request: NextRequest) => {
const authenticated = await runWithAmplifyServerContext({
nextServerContext: { cookies },
operation: async (contextSpec) => {
try {
const authSession = await fetchAuthSession(contextSpec, {});
return authSession.tokens !== undefined;
} catch (error) {
console.log(error);
return false;
}
},
});
if (authenticated) {
if (request.nextUrl.pathname !== "/login") return;
request.nextUrl.pathname = "/";
return NextResponse.redirect(request.nextUrl);
} else {
if (request.nextUrl.pathname === "/login") return;
request.nextUrl.pathname = "/login";
return NextResponse.redirect(request.nextUrl);
}
};
export default middleware;
Cognito グループによる認可処理
最後に、本題となるCognito グループによる認可処理を記述していきます。
先ほど取得したユーザセッションには Amplify によって検証が行われた JWT 形式のアクセストークンが含まれています。
JWT のペイロードは cognito:groups
という名前で認証ユーザの所属するグループを所持しています。このグループはグループ名の配列形式をとります。
["admin", "maintainer"]
const authSession = await fetchAuthSession(contextSpec, {});
+ const groups = authSession.tokens?.accessToken.payload[
+ "cognito:groups"
+ ] as string[] | undefined;
続いて、この配列を用いて認可を行います。
今回の例では、admin
グループと maintainer
グループに所属するユーザのみがアクセスできるようにします。
const authSession = await fetchAuthSession(contextSpec, {});
const groups = authSession.tokens?.accessToken.payload[
"cognito:groups"
] as string[] | undefined;
+ return !!(groups?.includes("admin") || groups?.includes("maintainer"));
これによって、groups?.includes("admin")
と groups?.includes("maintainer"))
が両方とも false
(または undefined
)のとき、全体として false
を返すようになりました。
最終的なコード
最終的なコードは以下のようになっています。
const middleware = async (request: NextRequest) => {
const authenticated = await runWithAmplifyServerContext({
nextServerContext: { cookies },
operation: async (contextSpec) => {
try {
const authSession = await fetchAuthSession(contextSpec, {});
const groups = authSession.tokens?.accessToken.payload[
"cognito:groups"
] as string[] | undefined;
return !!(groups?.includes("admin") || groups?.includes("maintainer"));
} catch (error) {
console.log(error);
return false;
}
},
});
if (authenticated) {
if (request.nextUrl.pathname !== "/login") return;
request.nextUrl.pathname = "/";
return NextResponse.redirect(request.nextUrl);
} else {
if (request.nextUrl.pathname === "/login") return;
request.nextUrl.pathname = "/login";
return NextResponse.redirect(request.nextUrl);
}
};
export default middleware;
おわりに
今回の記事では、Next.js の Middleware で Cognito グループによる認可処理を行う方法について解説しました。
Amplify では現状複数の Cognito プールと接続することはできないため、異なる属性を持つユーザを扱うためにはグループによる制御が欠かせません。
Next.js でグループによる認可制御を行う際は是非参考にしてみてください。
最後までお読みいただきありがとうございました。