강의

멘토링

로드맵

Programming

/

Front-end

Next + React Query で SNS サービスを作成する

React19 & Next15 & ReactQuery5 & Next Auth5 & MSW2 & socket.io4 & zustand 스택을 사용하여 Twitter(X.com)와 유사한 SNS 서비스를 만들어보겠습니다. 마지막으로 검색 엔진 최적화를 위한 SSR까지!

難易度 中級以上

受講期間 無制限

  • zerocho
Next.js
Next.js
React
React
react-query
react-query
next-auth
next-auth
msw
msw
Next.js
Next.js
React
React
react-query
react-query
next-auth
next-auth
msw
msw
zerocho님의 프로필 이미지

修正済み

next-auth サーバー エラーの受け取り & セッションにカスタム データの挿入 & 権限に応じてページにアクセス

こんにちは。ゼロ秒です。

多くの人がnext-authで一度苦しんでいたようです。まだベータなので、これまで少し不安定なことが多かったのですが、もう少し捕まっていくようです。そこで講義ではまだ機能がないので扱っていないが、追加されたものの3つを紹介します。

signIn時にフロントからサーバーエラーを受け取る

ログイン時にサーバーはさまざまなエラーを与えることができます。たとえば、1. ユーザーがいない場合 2. パスワードが間違っている場合 3. その他など。ところで、このようなものをフロントに渡さなければ状況に合ったメッセージを表示するのではないでしょうか。しかし、この基本的な機能がこれまでにないが今や追加されました。

auth.tsで次のように修正します。

 import NextAuth, {CredentialsSignin} from "next-auth" ... providers: [ CredentialsProvider({ async authorize(credentials) { const authResponse = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/login`, { ... }) // 여기 주목!!! 서버에서 에러가 발생할 때 그 에러 내용이 서버에 담겨 있을 겁니다. console.log(authResponse.status, authResponse.statusText) if (!authResponse.ok) { const credentialsSignin = new CredentialsSignin(); if (authResponse.status === 404) { credentialsSignin.code = 'no_user'; } else if (authResponse.status === 401) { credentialsSignin.code = 'wrong_password'; } throw credentialsSignin; } const user = await authResponse.json() console.log('user', user); // id, name, image, email만 허용 return { id: user.id, name: user.nickname, image: user.image, } }, }), ]

これで return null しないでCredentialsSignin エラーをスローします。エラーの属性であるコードにエラーメッセージを書き込むだけです。

 const response = await signIn("credentials", { username: id, password, redirect: false })

ログインに失敗した場合、responseにエラーコードとメッセージが含まれます。ただし、response.okはまだtrueになります(redirectがfalseの場合は無条件trueです)

session オブジェクトにカスタムデータを入れる

公式文書によると、現在のauthorize関数のreturnにはid、email、name、imageのみを入れることができます。これだけでも制限が大きいのにidは入れられるとしても入れるとuseSession()のデータでは消えてしまいます。

  1. それでは、idはどこに行きましたか?

  2. 他のカスタムデータはどのように入れますか?

    次のようにsessionを直接作成できます。

auth.ts

 export const { handlers: { GET, POST }, auth, signIn, } = NextAuth({ pages: { signIn: '/i/flow/login', newUser: '/i/flow/signup', }, callbacks: { async session({ session, token }) { console.log('session callback', session, token); const authResponse = await fetch(내정보를 가져오는 서버 API); const userData = await authResponse.json(); (session as any).userData = userData; return session; } }, providers: [ CredentialsProvider({ async authorize(credentials) { ... // id, name, image, email만 허용 return { id: user.id, name: user.nickname, image: user.image, }

このようにcallbacksプロパティにasync sessionメソッドを作成します。ここで私の情報をサーバーからもう一度呼び出すだけです。そしてその応答値を session オブジェクトに入れて返すのです。

  1. さっき消えたidはこのメソッドのtoken.subに入っています。

  2. ここで return する値が auth() や useSession() のデータになります。 authorizeでreturnした値が最終値ではなく、ここでもう一度修正されることです。

これにより、 auth() や useSession() で user.userData を確認できます。

権限に基づいてページにアクセスする

これで、sessionオブジェクトにカスタムデータを配置できるようになりましたので、権限に応じてページにアクセスできます。 callbacks.session async 関数で role のようなものをサーバーから受け入れて入れればいいです。 session.userData.roleにadminまたはnormal権限があるとしましょう。そして、 roleがadminの場合、アドミンページ(/admin)に接続可能でnormalであってはならないとしましょう。これをどのように実装できますか?

現在、middleware.tsは次のようになっていますが、これはconfigに少ないルートでのみ実行されるため、configをすべて削除します。

 import { auth } from "./auth" import {NextResponse} from "next/server"; export async function middleware() { const session = await auth(); if (!session) { return NextResponse.redirect('http://localhost:3000/i/flow/login'); } } // See "Matching Paths" below to learn more export const config = { matcher: ['/compose/tweet', '/home', '/explore', '/messages', '/search'], }

そしてmiddleware関数の中に手動で書くだけです。 request.nextUrl.pathnameに現在アクセスしたいパス名が含まれています。

 import { auth } from "./auth" import {NextResponse} from "next/server"; export async function middleware() { const session = await auth(); if (['/compose/tweet', '/home', '/explore', '/messages', '/search'].includes(request.nextUrl.pathname) && !session) { return NextResponse.redirect('http://localhost:3000/i/flow/login'); } }

このように修正した後、私たちは auth() の session から session.userData.role で権限にアクセスできるので、次のように検査後にリダイレクトするだけです。

 import { auth } from "./auth" import {NextResponse} from "next/server"; export async function middleware() { const session = await auth(); if (['/compose/tweet', '/home', '/explore', '/messages', '/search'].includes(request.nextUrl.pathname) && !session) { return NextResponse.redirect('http://localhost:3000/i/flow/login'); } if (request.nextUrl.pathname.startsWith('/admin') && session?.userData.role !== 'admin') { return NextResponse.redirect('http://localhost:3000/권한없음_알리는_모달_주소'); } }

このように不足しているnext-authを何らかの形で活用してみることができます。

次回も更新されることがありましたらお知らせします。ありがとうございます!

コメント