Next.js Callbacks 이용한 로그인 구현

이준석·2021년 10월 30일
6

Web

목록 보기
5/8
post-thumbnail

서론

저번 시간에는 NextAuth 를 이용한 로그인 구현 방식에 대해서 알아보았는데, 어제 방식을 이용하면 서버에서 session 을 이용해서 꺼낼 수 있는 데이터는 email, name, image 3가지가 끝이다.

하지만 사용자마다 session 에 저장하고 싶은 데이터가 있을텐데 어떻게 session 에 데이터를 저장할 수 있는지를 Callbacks 를 이용해서 살펴볼 예정이다.

보다 더 많은 정보를 확인하고 싶으면 아래의 공식 문서 참고

NextAuth Callbacks 공식 문서

본론

그럼 저번 포스팅의 코드에서 이어서 진행하도록 하겠습니다.

일단 [...nextauth].ts 파일을 열고 callbacks를 사용할 준비를 다음과 같이 한다.

import NextAuth from "next-auth"
import Providers from "next-auth/providers"
import {NextApiRequest} from "next";

export default NextAuth({
    providers: [
        Providers.Credentials({
           // 생략
          async authorize(credentials: Record<any, any>, req: NextApiRequest) {
                const email = credentials.email;
                const password = credentials.password;
                if (email === "test@test.com" && password === "test") {
                    return credentials;
                }
                throw new Error("아이디 혹은 패스워드가 틀립니다.");
            }
        })
    ],
    pages: {
        signIn: '/login',
    },
    // 아래 부분 추가
    callbacks: {
        async jwt(token, user, account, profile, isNewUser) {
            return token;
        },
        async session(session, userOrToken) {
            return session
        }
    }
})

공식문서를 보면 다음과 같이 작성되어있다.

If you want to pass data such as an Access Token or User ID to the browser when using JSON Web Tokens, you can persist the data in the token when the jwt callback is called, then pass the data through to the browser in the session callback.

간략하게 요약하면 무언가 데이터를 넘겨주고 싶으면 jwt 토큰에 데이터를 유지하고 session 에서 처리해주면 된다는 내용이다.

따라서 우리가 callbacks 에서 이용할 함수는 jwtsession 이다.

먼저, 로그인 이벤트가 발생하면 다음의 흐름으로 데이터가 흘러간다.

  1. providers 내부의 async authorize 에 인증을 실행
  2. callbacksjwt 함수가 실행
  3. callbackssession 함수가 실행

따라서 로그인 인증이 성공하면 jwt 함수에서 토큰이 생성되고 해당 토큰을 기반으로 session 이 생성되게 된다. 그럼 바로 코드를 작성해보도록 하자.

    callbacks: {
        async jwt(token, user, account, profile, isNewUser) {
            token.userId = 123;
            token.test = "test";
            return token;
        },
        async session(session: any, userOrToken: any) {
            session.user.userId = userOrToken.userId;
            session.user.test = userOrToken.test;
            return session
        }
    }

위의 코드를 설명하면 다음과 같다.

token 정보에다가 내가 커스텀으로 넣어주고 싶은 데이터를 다음과 같이 넣어준다.

token.userId = 123;
token.test = "test;

{
  ... 생략
  userId: 123,
  test: 'test'
}

그러고 token을 콘솔찍어보면 위와 같이 userIdtest 키 값으로 데이터가 들어간 모습을 확인할 수 있다.

그리도 async session 함수에서 userOrToken 파라미터로 토큰 정보를 받을 수 있고 다음과 같이 session에 데이터를 넣어준다.

session.user.userId = userOrToken.userId;
session.user.test = userOrToken.test;

그러면 최종적으로 session 데이터를 콘솔로 찍어보면 다음과 같이 데이터를 확인할 수 있다.

{
  name: null,
  email: 'test@test.com',
  image: null,
  userId: 123,
  test: 'test'
}

따라서 앞으로 서버에서 getSession 함수를 이용해서 데이터를 꺼내서 사용할 수 있는 폭이 userIdtest 로 늘어났다고 할 수 있다.

추가로 login.tsx 파일에서 signIn 함수안에 callbackUrl 을 설정해주고 로그인이 성공했을 때 페이지를 이동시킬 수 있다. 코드는 다음과 같다.

	// router에 있는 push 함수를 이용해서 페이지를 전환해줄 수 있다.
	const router = useRouter();
	const response: any = await signIn("email-password-credential", {
		email,
		password,
		redirect: false,
		callbackUrl: "http://localhost:3000/user"   // 추가
	});
	// response이 반환해주는 데이터 중 url이 callbackUrl에 정의된 내용이 들어온다.
	// response.url ==> http://localhost:3000/user
	await router.push(response.url) 	

그러면 로그인이 완료되었을 때 자동으로 http://localhost:3000/user 로 이동된다.
저번 시간에 안짚은 부분인 것 같아서 추가하겠습니다!

결론

아마 이정도의 지식만 있어도 NextAuth.js를 이용해서 로그인 부분을 구현하는데는 큰 지장이 없지 않을까 생각한다. 물론 데이터베이스 연결 부분과 에러 처리 등 안다룬 부분들이 존재하지만 그 부분들은 개발 하시면서 크게 어려운 부분은 아니라고 생각해서 제외하였습니다.

혹시라도 알고 싶으시다면 댓글 달아주시고, 최대한 안내해드리도록 하겠습니다.

그럼 이만 총총..

profile
호주 워홀중

4개의 댓글

comment-user-thumbnail
2022년 1월 21일

글 잘읽었습니다. 정말 큰 도움이 됬어요.
생각보가 지원되고 이미 구현되어 있는 Provider가 많아서 활용도가 높겠네요. 지금 v4 와 코드 차이가 약간 있어 해멨 지만 금방 적응할수 있었습니다.

감사합니다.

1개의 답글
comment-user-thumbnail
2022년 6월 7일

글 잘읽었습니다. 한가지 궁금하게 있습니다.
jwt callbacks를 정의하고나서 페이지 새로고침 시 token정보가 다시 token속성에 래핑되어 계속해서 내용 깊이가 깊어지는 문제가 발생하는데요.
혹시 해결방법을 아시는지요... 원인은 계속에서 jwt메서드가 호출되어서 token이 중첩되는거 같은데 해결책을 모르겠네요...

1개의 답글