🐱
Next.jsのサーバーサイドでユーザー認証しながらバックエンドのリソースにアクセスするためのメモ
getServerSideProps でのセッション情報取得
SSR のタイミングでバックエンドからデータ取得するにあたり、認証してないクライアントからのリクエストごとにバックエンドのリソースにアクセスをしたくないので getServerSideProps 実行時に Next Auth でセッション情報を取得する方法を探してみた。
結果的に「unstable_getServerSession」なる機能が試験的に実装されていたのでとりあえずそれを使ってみた。
実装方法(2022/10/4 時点)
pages/api/auth/[...nextauth].ts の修正
基本的な実装はこのような形になっているのを
import NextAuth from "next-auth";
/* import some providers */
export default NextAuth({
/* config */
});
設定の中身(NextAuthOptions)をエクスポートする。
import NextAuth from "next-auth";
import type { NextAuthOptions } from "next-auth";
export const authOptions: NextAuthOptions = /* config */
export default NextAuth(authOptions);
getServerSideProps を実装
サーバーサイドで認証を行いたいエンドポイントの getServerSideProps を実装する。
import type { GetServerSidePropsContext } from "next";
import { unstable_getServerSession } from "next-auth";
import { authOptions } from "../pages/api/auth/[...nextauth]";
export async function getServerSideProps(context: GetServerSidePropsContext) {
const session = await unstable_getServerSession(
context.req,
context.res,
authOptions
);
if (session) {
return { props: /* Authenticated Props */ };
} else {
return { props: /* Not authenticated Props */ };
}
}
実装例
試しに CosmosDB のチュートリアルになっている ToDoList から Items を認証時のみ引っ張ってこようとするとこうなる
import type { NextPage, GetServerSidePropsContext } from "next";
import { unstable_getServerSession } from "next-auth";
import { CosmosClient } from "@azure/cosmos";
import { authOptions } from "../pages/api/auth/[...nextauth]";
type Item = {
id: string;
category: string;
name: string;
description: string;
isComplete: boolean;
};
type Props = {
items?: Item[];
};
export async function getServerSideProps(
context: GetServerSidePropsContext
): Promise<{ props: Props }> {
const session = await unstable_getServerSession(
context.req,
context.res,
authOptions
);
if (session) {
const endpoint = process.env.COSMOS_DB_URI;
const key = process.env.COSMOS_DB_KEY;
const client = new CosmosClient({ endpoint, key });
const database = client.database("ToDoList");
const container = database.container("Items");
const { resources: items } = await container.items
.query({
query: "SELECT * from c",
})
.fetchAll();
return { props: { items } };
} else {
return { props: {} };
}
}
const Page: NextPage<Props> = ({ items }) => {
return <>/* implement components */</>;
};
export default Page;
Discussion