• 로그인
  • 장바구니에 상품이 없습니다.

home2 게시판 Next.js 게시판 소셜로그인 중복이메일처리

소셜로그인 중복이메일처리

  • 이 주제에는 16개 답변, 3명 참여가 있으며 김종엽2 년 전에 전에 마지막으로 업데이트했습니다.
10 글 보임 - 1 에서 10 까지 (총 16 중에서)
  • 글쓴이
  • #85175

    김종엽
    참가자
    작업환경
    1. 돈 없어서 윈도우
    2. vscode
    3. "next": "13.4.3",
    4. "next-auth": "^4.22.1",
    5."@next-auth/mongodb-adapter": "^1.1.3",
    6. "mongodb": "^5.5.0"
    7. recoil을 써보려고 온갖 수작 다 부려보다가 app모드(experimental app)에서 하는 방법을 도저히 몰라서
       app모드는 사용하지 않음. (기본 폴더구성 _app.tsx, _document.tsx)
    
    
    상황.
    현재 구글, 깃허브, 네이버, 카카오는 기능구현 완료 및 정상 동작 확인함. (아마도 될거에요..네..)
    그런데 예를 들어서, 깃허브 계정과 카카오계정이 "왜안돼@cordingApple.com" 일 때, 
    1. mongoDB에 먼저 가입한 계정의 정보만 들어가있고 (예를들어서 깃허브먼저가입하면 카카오는 정보가안들어감.)
    2. 깃허브 가입 후, 카카오 로그인버튼을 누르면 깃허브계정으로 연결이 됨.
    
     why를 생각해보면 아무리생각해봐도 중복된 이메일이 문젠거같은데, (다른 이메일로 된 깃허브계정을 만들어서 테스트해봤을 땐 이슈가 안남.)
    이럴떈 어떻게 코드를 조져주면 vscode가 헤벌쭉하면서 제가 원하는대로 깃허브,카카오 계정에 관한 DB가 딱딱 들어갈까요?
    
    근데 생각해보면 굳이 중복된 이메일을 처리해야하는 로직을 생각할 필요가있기도하고..(어차피 하나로 가입하면 만사ok니까 사용자 입장에선 중복이고 나발이고 이슈가 날 이유가 없잖아요..)
    근데 또 4개 다 들어가있는걸 봐야 직성이 풀리니까 조언을 구하고 싶어요 선생님.
    그리고 사실 이 질문 말고도 보따리 속에 500개 정도 더 있음.
    
    
    추가로 해주시면 너무나도 감사할 것 같은 것.
    : 나름 짱구돌린다고 신나게 구글링조져서 코드짜본건데...  피드백도 듣고싶습니당...
    
    엄청 대충하는 코드리뷰.
    1. 각각 플랫폼에 가서 어플리케이션 만든 뒤, 리다이렉트 url : http://localhost:3000/api/auth/callback/kakao 등 구글링해서 하라는 짓 다 함.(된거보면 세팅은 맞게 한거같음)
    2. [...nextauth].ts에 provider를 이쁘게 줌.
    3. signIn()을 이용해서 소셜 로그인 기능을 구현.
    
    코드
    
    1. [...nextauth].ts
    
    
    import bcrypt from "bcrypt"
    import NextAuth, { AuthOptions } from "next-auth"
    import CredentialsProvider from "next-auth/providers/credentials"
    import GithubProvider from "next-auth/providers/github"
    import GoogleProvider from "next-auth/providers/google"
    import NaverProvider from "next-auth/providers/naver"
    import KakaoProvider from "next-auth/providers/kakao"
    import { MongoDBAdapter } from "@next-auth/mongodb-adapter"
    import connectDB from "@/pages/@lib/mongoDB"
    export const authOptions: AuthOptions = {
      providers: [
        GithubProvider({
          clientId: process.env.GITHUB_ID!,
          clientSecret: process.env.GITHUB_SECRET!,
          allowDangerousEmailAccountLinking: true,
        }),
        GoogleProvider({
          clientId: process.env.GOOGLE_CLIENT_ID!,
          clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
          allowDangerousEmailAccountLinking: true,
        }),
        NaverProvider({
          clientId: process.env.NAVER_CLIENT_ID!,
          clientSecret: process.env.NAVER_CLIENT_SECRET!,
          allowDangerousEmailAccountLinking: true,
        }),
        KakaoProvider({
          clientId: process.env.KAKAO_CLIENT_ID!,
          clientSecret: process.env.KAKAO_CLIENT_SECRET!,
          allowDangerousEmailAccountLinking: true,
        }),
        CredentialsProvider({
          //1. 로그인페이지 폼 자동생성해주는 코드
          name: "credentials",
          credentials: {
            email: { label: "Email", type: "email" },
            password: { label: "Password", type: "password" },
          },
          //2. 로그인요청시 실행되는코드
          //직접 DB에서 아이디,비번 비교하고
          //아이디,비번 맞으면 return 결과, 틀리면 return null 해야함
          async authorize(credentials, req) {
            if (!credentials?.email || !credentials?.password) {
              throw new Error("Invalid credentials")
            }
            let db = (await connectDB).db("Restay")
            let user: any = await db
              .collection("users")
              .findOne({ email: credentials.email })
            if (!user) {
              throw new Error("해당 이메일은 없음")
            }
            const pwcheck = await bcrypt.compare(
              credentials.password,
              user.password,
            )
            if (!pwcheck) {
              throw new Error("Invalid credentials")
            }
            // return { id: user._id.toString(), name: user.name, email: user.email }
            return user
          },
        }),
      ],
      // 3. jwt 써놔야 잘됩니다 + jwt 만료일설정
      session: {
        strategy: "jwt",
        maxAge: 30 * 24 * 60 * 60, //30일
      },
      callbacks: {
        //4. jwt 만들 때 실행되는 코드
        //user변수는 DB의 유저정보담겨있고 token.user에 뭐 저장하면 jwt에 들어갑니다.
        jwt: async ({ token, user }: any) => {
          if (user) {
            token.user = {}
            token.user.name = user.name
            token.user.email = user.email
            token.user.image = user.image
          }
          return token
        },
        //5. 유저 세션이 조회될 때 마다 실행되는 코드
        async session({ session, token }: any) {
          // Send properties to the client, like an access_token and user id from a provider.
          session.user = token.user
          session.providerType = token.providerType
          return session
        },
      },
      pages: {
        signIn: "/",
      },
      debug: process.env.NODE_ENV === "development",
      secret: process.env.mongoDB_SECRET,
      adapter: MongoDBAdapter(connectDB),
    }
    export default NextAuth(authOptions)
     
    2.  버튼 속 signIn()
     <Button
              outline
              label={"Google로 시작하기"}
              icon={FcGoogle}
              onClick={() => {
                signIn("google")
              }}
            />
    // 이런식으로 버튼 4개 만들었음. 
    
    
    
    
    
    
    
     
    #85176

    김종엽
    참가자
    원래 글 제목은 "소셜로그인 기능 구현 도중, 중복이메일처리에대한 로직에 대해서 조언을 구하고 싶습니다."
    입니다. 제목이 너무길다고 계쏙 reject먹어서 본의아니게 짧은말 미리 죄송요 썜.
    #85208

    codingapple
    키 마스터
    allowDangerousEmailAccountLinking: true 해놓으면 이메일같은사람 자동으로 연결해주니까 
    이거 빼면 되는거 아닐까요
    #85215

    김종엽
    참가자
    allowDangerousEmailAccountLinking: true 를 넣어줬던 이유가 안넣으면 주소창이
    http://localhost:3000/?callbackUrl=http%3A%2F%2Flocalhost%3A3000%2F&error=OAuthAccountNotLinked
    라고 뜨면서 로그인이 안됩니다 ㅜㅜ
    
    계속 쿼리스트링으로 callbackUrl error OAuthAccountNotLinked라고 떠가지고 [...nextauth].ts에서 이짓저짓
    다해보다가 allowDangerousEmailAccountLinking을 넣어주니까 작동이 잘되더라고요...ㅜㅜ
    
    
    #85217

    codingapple
    키 마스터
    OAuthAccountNotLinked 에러가날 경우 이미 가입된 계정 있다고 메세지 띄우면 되는데 
    https://logfetch.com/next-auth-custom-error-page/ 이런거 찾아봅시다 
    
    #85346

    김종엽
    참가자
    "OAuthAccountNotLinked 에러가날 경우 이미 가입된 계정 있다고 메세지 띄우면 되는데" 부분이 잘 이해가지 않습니다.
    OAuthAccountNotLinked 이슈상황에 대해 조금 설명을 드리자면..
    OAuthAccountNotLinked 이슈가 발생하면 mongoDB에 데이터가 없을떄 (소셜로그인 맨처음할떄)는 원하는대로 작동을 잘합니다. (세션도 잘 받아와져요.)
    근데 2번쨰부터는 주소창에 http://localhost:3000/?callbackUrl=http%3A%2F%2Flocalhost%3A3000%2F&error=OAuthAccountNotLinked라고 뜨면서 로그인이 되지 않습니다.
    
    강의 내용을 했을 때는 OAuth는구글,깃허브만 했었고, 두번째 로그인에도 이슈가 없었는데, 새로운 프로젝트를 만들고 배웠던걸 토대로 네이버 카카오를 도전해보려하니까 이런 이슈가 발생한 상황입니다. ㅜㅜ
    OAuth에 대해 깊게 파고든게 아니고 "nextauth에서 제공하는 signIn()으로 되는거다" 만으로 접근하니까 원인파악이 더 어렵네요..
     
    왜 구글,깃허브는 되고 네이버카카오는안되는지 잘모르겠습니다..ㅜㅜ 선택받지못한걸까요
    
    
    PS. allowDangerousEmailAccountLinking: true 는 https://github.com/nextauthjs/next-auth/issues/519 여기를 참고했습니당..
    
    #85356

    codingapple
    키 마스터
    이미 가입했던 이메일로 로그인시도하는경우 
    자동으로 기존계정 연결되는게 싫으면 allowDangerousEmailAccountLinking 빼면 됩니다
    자동연결안되고 OAuthAccountNotLinked 에러나면 이미 같은 이메일로 가입했었다고 에러페이지 만들어주면 됩니다
    
    #85367

    김종엽
    참가자
    시작하기전 ps.. 왜인지 모르겠는데 엄청 길어서 그런가 글올리기로 했는데 글이 안 올라가네요.. 2회차 적는 중 입니다 ㅜㅜ. 또한 다음 페이지까지 내용이 이어져요.. 폭탄죄송합니다..
    질문을 조금 수정하겠습니다.
    원인을 찾은 것 같습니다.
    그래서 새로운 고민들이 생겼습니다.
    환경.
    위의 [...nextauth].ts 코드와 동일하게 adapter와 debug를 사용하고 있습니다.
    상황.
    debug로 인해, 소셜로그인을 시도할 때, 터미널에 이런 진행상황들이 나옵니다.
    [next-auth][debug][CREATE_STATE] { value: 'UKosGz8pA_XrbjOtgknapdO35jvx9D3PixidVFo0GVo', maxAge: 900 }
    [next-auth][debug][GET_AUTHORIZATION_URL] {
      url: 'https://github.com/login/oauth/authorize?client_id=549398bb3fd52db8cd63&scope=read%3Auser%20user%3Aemail&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fcallback%2Fgithub&state=UKosGz8pA_XrbjOtgknapdO35jvx9D3PixidVFo0GVo',
      cookies: [
        {
          name: 'next-auth.state',
          value: 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0.._h2gjAS_6pZBalVO.6OUh9Kk5V11HDfokBpRIEIsTTE9V8bgeDp9NrkTxZS-AhqY_GoTRw5uDvObR68CYJKdGyrd6d2yZgSaK0FBDXxAUQUf19qPR3iKoqcmlkAXnVsufhVrUQCfG5LC1h3S6Yp_sMMNCdj4ZBm7Y5dN7oRCkrgogRjetEhLv6XV1v5AhWo2PzdU.Zv_lpXLbS-IeCEYhuxMvMQ',
          options: [Object]
        }
      ],
      provider: {
        id: 'github',
        name: 'GitHub',
        type: 'oauth',
        authorization: {
          url: 'https://github.com/login/oauth/authorize',
          params: [Object]
        },
        token: { url: 'https://github.com/login/oauth/access_token', params: {} },
        userinfo: {
          url: 'https://api.github.com/user',
          request: [AsyncFunction: request]
        },
        profile: [Function: profile],
        style: {
          logo: '/github.svg',
          logoDark: '/github-dark.svg',
          bg: '#fff',
          bgDark: '#000',
          text: '#000',
          textDark: '#fff'
        },
        idToken: false,
        checks: [ 'state' ],
        clientId: '549398bb3fd52db8cd63',
        clientSecret: 'a5372d1492f571519f63975dd6e2c3deef919bfb',   
        signinUrl: 'http://localhost:3000/api/auth/signin/github',  
        callbackUrl: 'http://localhost:3000/api/auth/callback/github'
      }
    }
    #85368

    김종엽
    참가자
    [next-auth][debug][PROFILE_DATA] {
      OAuthProfile: {
        login: 'PracticeKJY',
        id: 119389577,
        node_id: 'U_kgDOBx29iQ',
        avatar_url: 'https://avatars.githubusercontent.com/u/119389577?v=4',
        gravatar_id: '',
        url: 'https://api.github.com/users/PracticeKJY',
        html_url: 'https://github.com/PracticeKJY',
        followers_url: 'https://api.github.com/users/PracticeKJY/followers',
        following_url: 'https://api.github.com/users/PracticeKJY/following{/other_user}',
        gists_url: 'https://api.github.com/users/PracticeKJY/gists{/gist_id}',
        starred_url: 'https://api.github.com/users/PracticeKJY/starred{/owner}{/repo}',
        subscriptions_url: 'https://api.github.com/users/PracticeKJY/subscriptions',
        organizations_url: 'https://api.github.com/users/PracticeKJY/orgs',
        repos_url: 'https://api.github.com/users/PracticeKJY/repos',    events_url: 'https://api.github.com/users/PracticeKJY/events{/privacy}',
        received_events_url: 'https://api.github.com/users/PracticeKJY/received_events',
        type: 'User',
        site_admin: false,
        name: 'KJY',
        company: null,
        blog: '',
        location: null,
        email: 'poiijtl1004@naver.com',
        hireable: null,
        bio: '개발 잘하고 싶은 개발자지망생',
        twitter_username: null,
        public_repos: 30,
        public_gists: 0,
        followers: 2,
        following: 9,
        created_at: '2022-11-29T03:59:55Z',
        updated_at: '2023-05-31T11:33:27Z',
        private_gists: 0,
        total_private_repos: 3,
        owned_private_repos: 3,
        disk_usage: 63646,
        collaborators: 0,
        two_factor_authentication: false,
        plan: {
          name: 'free',
          space: 976562499,
          collaborators: 0,
          private_repos: 10000
        }
      }
    }
    #85369

    김종엽
    참가자
    [next-auth][debug][OAUTH_CALLBACK_RESPONSE] {
      profile: {
        id: '119389577',
        name: 'KJY',
        email: 'poiijtl1004@naver.com',
        image: 'https://avatars.githubusercontent.com/u/119389577?v=4'
      },
      account: {
        provider: 'github',
        type: 'oauth',
        providerAccountId: '119389577',
        access_token: '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',   
        token_type: 'bearer',
        scope: 'read:user,user:email'
      },
      OAuthProfile: {
        login: 'PracticeKJY',
        id: 119389577,
        node_id: 'U_kgDOBx29iQ',
        avatar_url: 'https://avatars.githubusercontent.com/u/119389577?v=4',
        gravatar_id: '',
        url: 'https://api.github.com/users/PracticeKJY',
        html_url: 'https://github.com/PracticeKJY',
        followers_url: 'https://api.github.com/users/PracticeKJY/followers',
        following_url: 'https://api.github.com/users/PracticeKJY/following{/other_user}',
        gists_url: 'https://api.github.com/users/PracticeKJY/gists{/gist_id}',
        starred_url: 'https://api.github.com/users/PracticeKJY/starred{/owner}{/repo}',
        subscriptions_url: 'https://api.github.com/users/PracticeKJY/subscriptions',
        organizations_url: 'https://api.github.com/users/PracticeKJY/orgs',
        repos_url: 'https://api.github.com/users/PracticeKJY/repos',    events_url: 'https://api.github.com/users/PracticeKJY/events{/privacy}',
        received_events_url: 'https://api.github.com/users/PracticeKJY/received_events',
        type: 'User',
        site_admin: false,
        name: 'KJY',
        company: null,
        blog: '',
        location: null,
        email: 'poiijtl1004@naver.com',
        hireable: null,
        bio: '개발 잘하고 싶은 개발자지망생',
        twitter_username: null,
        public_repos: 30,
        public_gists: 0,
        followers: 2,
        following: 9,
        created_at: '2022-11-29T03:59:55Z',
        updated_at: '2023-05-31T11:33:27Z',
        private_gists: 0,
        total_private_repos: 3,
        owned_private_repos: 3,
        disk_usage: 63646,
        collaborators: 0,
        two_factor_authentication: false,
        plan: {
          name: 'free',
          space: 976562499,
          collaborators: 0,
          private_repos: 10000
        }
      }
    }
    [next-auth][debug][adapter_getUserByAccount] { args: [ { providerAccountId: '119389577', provider: 'github' } ] }
    [next-auth][debug][adapter_getUserByAccount] { args: [ { providerAccountId: '119389577', provider: 'github' } ] }
    [next-auth][debug][adapter_getUserByEmail] { args: [ 'poiijtl1004@naver.com' ] }
    원인.
    작동이 [next-auth][debug][adapter_getUserByEmail] { args: [ 'poiijtl1004@naver.com' ] } 여기에서 멈춰서 그렇습니다.
    아래와 같은 과정이 필요합니다.
    [next-auth][debug][adapter_linkAccount] {
      args: [
        {
          provider: 'kakao',
          type: 'oauth',
          providerAccountId: '2792713047',
          access_token: 't1GL8hWXODkrV0MCyFpndMEkUOPGvuPD_D8XJwURCj1z6wAAAYhxwsrX',
          token_type: 'bearer',
          refresh_token: 'yljr3YbEzD6IwbSZZ650ekAIUkrDtwHQ-RSlBweUCj1z6wAAAYhxwsrW',
          expires_at: 1685557370,
          scope: 'account_email profile_image profile_nickname',    
          refresh_token_expires_in: 5183999,
          userId: '64759cdd334e4e067c524866'
        }
      ]
    }
10 글 보임 - 1 에서 10 까지 (총 16 중에서)
  • 답변은 로그인 후 가능합니다.

About

현재 월 700명 신규수강중입니다.

  (09:00~20:00) 빠른 상담은 카톡 플러스친구 코딩애플 (링크)
  admin@codingapple.com
  이용약관
ⓒ Codingapple, 강의 예제, 영상 복제 금지
top

© Codingapple, All rights reserved. 슈퍼로켓 에듀케이션 / 서울특별시 강동구 고덕로 19길 30 / 사업자등록번호 : 212-26-14752 온라인 교육학원업 / 통신판매업신고번호 : 제 2017-서울강동-0002 호 / 개인정보관리자 : 박종흠