[NJ(308)]“크리덴셜 인증 제공자” & 사용자 로그인 논리 추가하기

이유정·2024년 4월 28일
0

Next.js (pages router)

목록 보기
38/42

지난 시간



사용자를 생성할 수 있게 만듬

인증 기능 설정

인증을 통해 사용자를 로그인하고, 로그인 권한을 얻으며 다시말해, 로그인된 사용자의 토큰을 얻고 사용자의 로그인을 확인할 수 있음.

  • 보이는 것을 바꾸고
  • 특정 라우트를 비활성화하는 client side
  • 추가될 여러 api 라우트의 server side
    => 양쪽에 로그인했는지 확인

NextAuth 가 필요해짐.
이 패키지를 통해 우리는 1) 사용자를 인증하고 2) 사용자가 권한을 가지는지 여부를 확인할 수 있음.

  • 해당 토큰의 생성 및 저장을 관리함으로써 가능.
  • 내부에서 일어남.


NextAuth 를 이용하기 위해 다른 api를 추가해야 한다.

  • 사용자가 로그인할 때도 특정 api 라우트로 전송할 요청이 필요하기 때문.
    • 그러면, 우리는 db를 살펴보고 그 db에 사용자가 존재하는지 비밀번호는 맞는지 확인하게 됨.
  • 동적 api 라우트로 생성.
    • 동적 catch-all API 라우트로서 api/auth로 시작하는 모든 알 수 없는 라우트를 잡아낸다.

NextAuth 패키지가 내부에서 여러 라우트를 활용한다.

  • ex) 사용자 로그인 or 사용자 로그아웃
  • catch-all 라우트를 사용해서 이 특별한 라우트를 향한 요청을 NextAuth 패키지가 모두 자동으로 처리하도록 한다.
  • 추가로, signup 라우트 같은 자체 라우트를 정의할 수도 있음.
    • NextAuth의 내장된 경로를 오버라이드 하지 않는 한 가능
    • NextAuth가 생성하는 api
      • 전부 /api/auth 로 시작하고 NextAuth에서 처리됨.
      • 그러니 충돌하지 않게 해야함.

코드 작성


/api/auth/[...nextauth].js
NextAuth를 실행시키면 새로운 함수 handler() 함수를 반환한다.

  • api 라우트는 여전히 함수를 반환해야 한다.
  • 다만, 내보낸 handler() 함수는 NextAuth()를 호출함으로써 NextAuth()에 의해 생성된다.


NextAuth()를 호출할 때 구성 객체를 전달할 수 있는데 그 객체를 통해 NextAuth()의 동작을 구성할 수 있다.


configuration의 Options에서 필수 설정 옵션을 볼 수 있다.

  • 우리는 providers 옵션을 설정 !
    • 배열로 설정

  • providers 배열에서 Providers.을 사용하고 수많은 옵션 중 Credentials 사용
    • 고유의 크리덴션을 제공하겠다는 뜻.

이때 구성 객체 자체가 필요한데 몇 가지를 구성할 수 있다.
credential이 무엇인지 정의해보자.

  • 이메일
  • 비밀번호
    => 그렇게 NextAuth가 우리 대신 로그인 양식을 만들어준다. 하지만, 지금은 NextAuth가 양식을 생성할 필요가 없다. (이미 하나 갖고 있음)

여기서 설정해야 할 한 가지는 바로 authorize이다.
들어오는 login 요청을 Next.js가 수신할 때 우리 대신 호출해주는 메서드.


비동기 함수인 authorize()는 프로미스를 반환한다.

제출된 credentials을 인수로 얻는다. 바로, 우리가 제출한 data가 있는 객체임. (이메일, 비밀번호)

credentails이 유효한지 확인하고, 아니라면 사용자에 알릴 것.
예를들어) 유효하지 않으면 사용자에 알릴 것. 에러 표시

db랑 연결하고 나중에 close까지 작성 미리하기.

입력된 이메일 사용자가 있는지 확인하고 비밀번호도 맞는지 확인할 것임.


db를 확인해서 'users' 쪽을 본다. 그리고 해당하는 email이 있는지 찾아본다.


만약 user가 없다면 error 던져

  • authorize() 내부에서 에러가 발생하면, authorize()가 생성한 프로미스를 거부하고, 기본적으로 client를 다른 page에 redirection 한다.
    • 하지만 이 함수를 overwirte 하면 login page에 머물며 error를 보여줄 수 있음 (이건 나중에 해보자)


알다시피 비밀번호를 hash 했기 때문에 제출된 비밀번호와 저장된 비밀번호를 그냥 비교할 수 없음. compare를 통해서 평문 비밀번호의 결과가 hashedPassword 인지 확인하고 만약 그렇다면 비밀번호가 일치하다는 뜻 !

코드 작성 완료한 상태


첫번째 인수는 : 사용자가 작성한 비밀번호
두번째 인수는 : MongoDB에 저장된 password 필드에 access 된다.


그런데, veryfyPassword()가 비동기 함수라 프로미스를 반환함.


만약 비밀번호가 일치하지 않는다면 throw new Error!


user도 존재하고 , 비밀번호도 맞다면 로그인이 되어야 한다.
이때, 객체를 반환한다.
그리고, 이 객체는 해당 json의 web token으로 부호화될 것.

  • 그래서, user.email이 포함될 수 있음.
  • 전체 user 객체를 전달할 수는 없음. 비밀번호는 포함시킬 수 없기 때문임. (해싱된 비번도 안됨)


따라서 이렇게 객체를 반환하면 json web token으로 부호화된다.


json web token이 생성되었는지 확인해보자.

  • session 옵션을 사용할 수 있음.
    • 인증된 사용자에 대한 session을 관리하는 방법 구성할 수 있게 하는 객체

      jwt를 true로 설정해서 json web token을 사용할 수 있게 하자.
  • 다른 기타 인증 제공자의 경우 다른 방식으로 관리할 수 있는데 예를 들어, 세션은 db에 저장된다.
  • 그러나 우리가 진행중인 이 제공자에 대한 credential 기반 인증의 경우 무조건 jwt 를 사용해 true로 설정해야 한다.

    만약 db를 설정하지 않으면, 자동으로 jwt 값은 true가 된다.
    우리는 db를 지정하지 않고 있음. 이 특정한 공급자로 db access를 모두 직접 처리하니까.

    만약, 다른 제공자를 사용할 경우 당연히 db를 추가하고 session을 사용할 수 있다. 어떤 인증 제공자를 사용하냐에 따라 다름.
  • 만약 Email이라면 링크가 포함된 이메일이 전송된다. => 그러면, 이메일이 저장될 db를 추가해야함. jwt를 사용할 필요는 없음.


우리는,

  • jwt를 사용하고
  • credential을 사용하니까
    이렇게 구성하는 것이 맞음!

우리가 만든 이 api 라우트를 사용해서 로그인 확인 요청을 전송하기 전에 한가지 해야 할 일이 있다.

  • client.close()는 return 이전에 호출되고
  • error를 띄울 경우에도 호출되어야 db를 닫을 수 있음.
profile
팀에 기여하고, 개발자 생태계에 기여하는 엔지니어로

0개의 댓글