0421 CLANBE 개발일지

dowon kim·2024년 4월 21일
0

CLANBE

목록 보기
8/11

오늘은 next-auth를 적용한 로그인 기능 과 글작성 기능 구현으로 하루를 보냈다.

미들웨어

export { auth as middleware } from "./auth"

// Or like this if you need to do something here.
// export default auth((req) => {
//   console.log(req.auth) //  { session: { user: { ... } } }
// })

// Read more: https://nextjs.org/docs/app/building-your-application/routing/middleware#matcher
export const config = {
  matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
}

auth.ts

import NextAuth from "next-auth";
import type { NextAuthConfig } from "next-auth";
import Credentials from "next-auth/providers/credentials";

export const config = {
  providers: [
    Credentials({
      credentials: {
        email: { label: "Username", type: "text" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        const { email, password } = credentials;

        try {
          const response = await fetch(`${process.env.NEXT_AUTH_URL}`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ signInState: { email, password } }),
        });

          const data = await response.json();

          if (response.ok && data.user) {
            return data.user; // 성공적으로 사용자 정보를 받음
          } else {
            // API에서 반환된 에러 메시지 사용 또는 기본 에러 메시지 설정
            throw new Error(data.message || '로그인에 실패했습니다. 다시 시도해 주세요.');
          }
        } catch (error:any) {
          // catch 블록에서 오류를 잡아 에러를 던집니다.
          throw new Error(error.message || '로그인 처리 중 오류가 발생했습니다.');
        }
      }
    }),
  ],
  pages: {
    signIn: "/AUTH/signin", // 사용자 정의 로그인 페이지
    // 기타 페이지 설정 생략...
  },
  basePath: "/api/auth",
  callbacks: {
    authorized({ request, auth }) {
      const { pathname } = request.nextUrl;
      alert(pathname);
      if (pathname === "/AUTH/signin") return !!auth;
      return true;
    },
    jwt({ token, user }) {
      if (user) {
        // 사용자 정보 확장 필드 추가
        token.avatar = user.avatar;
        token.name = user.name;
        token.nickname = user.nickname;
        token.role = user.role;
        token.grade = user.grade;
        token.point = user.point;
        token.tear = user.tear;
        token.BELO = user.BELO;
        token.team = user.team;
      }
      return token;
    },
    session({ session, token }) {
      // 세션 정보에 토큰에서 사용자 정보를 추가
      if (token) {
        session.user = {
          avatar: token.avatar as string,
          name: token.name as string,
          nickname: token.nickname as string,
          point: token.point as number,
          BELO: token.BELO as any,
          email: token.email as string,
          role: token.role as string,
          grade: token.grade as number,
          tear: token.tear as string,
          team: token.team as string,
          id: "default-id", // 필요한 경우 token에서 id를 가져오거나 기본 id 제공
          emailVerified: null, // emailVerified는 null이 가능
        };
      }
      return session;
    },
  },
  session: {
    strategy: "jwt",
  },
  secret: `${process.env.NEXT_AUTH_SECRET}`,
} satisfies NextAuthConfig;

export const { handlers, auth, signIn, signOut } = NextAuth(config);

app/api/[...nextauth]/route.ts

import { handlers } from "../../../../../auth";

export const { GET, POST } = handlers

다음과 같이 미들웨어와 auth 로직 및 api를 구성했다.

그 과정에서 기존 auth 라이브러리의 타입정의로 인한 반환값 에러를 직면하게 되었는데,

라이브러리 공식 타입 지정은 이렇게 네개의 필드를 반환할 수 있지만,

나는 토큰과 세션에 유저의 데이터를 저장하고 조회하는 방식으로 개발을 원하기에

기존 타입을 확장시켜야 했다.

import 'next-auth';

declare module 'next-auth' {
  export interface User {
    avatar: string;
    nickname: string;
    email: string;
    name: string;
    role: string;
    grade: number;
    point: number;
    tear: string;
    BELO: {
      race: string;
      pw: number;
      pl: number;
      tw: number;
      tl: number;
      zw: number;
      zl: number;
    };
    team: string;
  }
}

해당 커스텀 타입을 통해 타입에러를 잡고 정상적으로 세션을 통해 유저정보를 클라이언트에서 유지할 수 있게되었다.

다만 매우 불쾌한 버그가 하나 있었다.

바로 로그인 실패시 에러 스테이터스가 200으로 고정되는 문제였는데,

로그인 실패성공 여부 자체야 user 객체가 성공적으로 반환됬느냐 아니냐에 따라 쉽게 판가름 할 수야 있다.

그러나 왜 실패했는지에 대해서 구분해 줄 방법이 없는 것이다.

구글링 및 라이브러리 공식 레포의 issue들을 뒤져본 결과

해당 문제가 버그라는 의견과 애초에 next-auth에서 의도한 동작이라는 의견등을 찾을 수 있었다.

이 프로젝트가 많은 사람들이 실제로 이용하게 될 서비스이기 때문에 이런 사소한 부분도 놓치고 싶지 않아서

next-auth를 뜯어내 버릴까 굉장히 긴시간 동안 고민을 하게 되었지만

일단은 사이트 로직에 문제가 없기때문에 진행하면서 계속 디버그 시도를 하려고 한다.

확실히 이번 프로젝트가 기존과는 다르게 참고할 레퍼런스나 강의등이 전혀 없이 직접 개발하고 있다보니

이것이 정답이다 하는 옳바른 방향이 없어 중간중간 생각에 잠기면서 시간을 뺏기는 경우가 많은 것 같다.

그러나 이런경험을 하는 것도 이 프로젝트 방향성에 맞는 경험치라고 생각하기 때문에

같은상황에 직면했을때 점차 효율적으로 빠르게 빠져나오는 방향의 발전을 이루고 싶다.

profile
The pain is so persistent that it is like a snail, and the joy is so short that it is like a rabbit's tail running through the fields of autumn

0개의 댓글