Github Login #06

0_CyberLover_0·2022년 4월 24일
0

Node.JS #05

목록 보기
6/19

이제 스스로에게 물어본다(?)

"로그인 규칙을 어떻게 만들것인가?" 예를 들어, 데이터베이스에

user가 하나 있는데 이 user는 이런 email을 가지고 있다.

{ "_id" : "yuoIkA5t7NB_axs1qVST5xflGbrR45jh", "expires" : ISODate("2022-05-06T07:39:42.013Z"), "session" : "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"},\"loggedIn\":true,\"user\":{\"_id\":\"625942ace3564e09811a5f21\",\"email\":\"pkpanda@naver.com\",\"username\":\"Cyber Lover\",\"password\":\"$2b$05$WMO/VH/yctvvPJST0SyLq.QRQfSNeLJ5zAJPFfRMwLgg5ZFq1KtBm\",\"name\":\"Mercury\",\"location\":\"NYC\",\"__v\":0}}" }

이미 해당 email로 계정도 있고 password도 있다.

즉 이 userusernamepassowordlogin을 할수 있다.

그런데 만일 Github으로 로그인 버튼을 누르게 된다면 토큰 작업등 전부 거친 뒤

Github으로 로그인 한user는 데이터베이스상에 똑같은 emailpassword를 가진 user를 받는다.

그러니까 웹사이트로 와서 emailpassword로 계정을 생성하고 한달 후에 돌아와서

Github으로 로그인 하려한다.

보다시피 Githubemail을 주고 있다. 그런데 이 email이 똑같다.

그러면 어떻게 하는게 좋을까? 두가지 옵션이 있다. 하나는 user에게 "그건 안된다.

이미 password가 있으니 그걸로 로그인하라" 라고 말 할수 있고

또는 "똑같은 email이 있다는걸 증명했으니 Github로 로그인해도 된다" 라고 할수 있다.

만일 user가 다른 무언가로 로그인을 했다면 예를 들어 카카오톡으로 로그인 했다하면

카카오톡이 이런식으로 email을 줄거다. 이렇게 user를 로그인 시킬수도 있다.

이런 방식을 채택한 여러 사이트들이 있다. 그치만 몇몇 사이트들은 password로 계정을 만들게 하는 곳도 있다.

"password로 로그인 하세요"라고 하면서 말이다.

혹은 emailpassword로만 로그인하려 하는데 사실 password없이 Github 로그인으로

계정을 만들었다면 "user는 있지만 password는 없다. 그러니까 Github로 로그인해라" 라고 할거다.

보다시피 옵션은 정말 많다. 그래서 Github로그인 같은 소셜 로그인을 할때

만일 email에 접근 권한이 있다는게 증명이 된다면 즉, password가 있거나

Githubemailverified된거라면 email의 주인이라는 뜻이니까

로그인 시켜 줄수 있다. 꼭 이렇게 할 필요는 없다. 더 많은 조건들을 만들어도 된다.

예를 들어 userpassword를 갖고 있다는걸 알게 된다면 로그인을 시켜선 안되는 거다.

이 같은 경우엔 여기에 primaryverified가 있기 때문에 그렇게 하지 않는다.

그래서 primary이면서 verifiedemail을 찾는거다. 두개다 중요하기 때문이다.

그래서 user가 두개의 조건을 만족한다면 "email이 있으니 로그인 시켜준다"라고 할거다.

이 부분 또한 바뀐다. 예를 들어 Github login으로 계정을 만든 user있을때

email은 있지만 password가 없는 경우를 말하는 거다.

이럴때는 로그인 화면에서 user에게 이렇게 말해야 한다.

"email은 있는데 password가 없다"이건 그들이 Github으로 로그인해야 한다는 뜻이다.

이렇게 고려해야 할 사항들이 굉장히 많다.

이제 무엇을 하냐면 만약 primaryemail을 받고 데이터베이스에서 같은 email을 가진 user를 발견하면

user들을 로그인 시켜 준다. email은 사실 string이 아닌 객체 이다.

그래서 find가 객체를 주고 있는 거다. 그런데 email그 자체가 필요하다.

이 부분을 emailObj라 바꿔 본다.

    const emailObj = emailData.find(
      (email) => email.primary === true && email.verified === true
    );
    if (!emailObj) {
      return res.redirect("/login");
    }
    const existingUser = await User.findOne({ email: emailObj.email });
    if (existingUser) {
      req.session.loggedIn = true;
      req.session.user = user;
      return res.redirect("/");
    }
  } else {
    return res.redirect("/login");
  }
};

그리고 기존 user를 찾는거다. 그리고 emailObj.email을 가지고 user를 찾는다.

만일 해당 email을 가지는 user가 이미 있다면 그 유저가 전에 Github로 로그인했든

password로 계정을 생성했든 신경 쓰지 않는다.

핵심은 해당 email을 가진 user가 이미 있는지 찾는 것이고 이런 유저를 로그인 시켜 줄거다.

로그인은 어떻게 시키냐면 위에서 있는 코드가 있으니 그것을 그대로 활용한다.

req.session.loggedIn = true;
req.session.user = user;

return res.redirect()을 써서 "/"/으로 돌아가게 한다.

하지만 이번에는 로그인이 된 상태가 된다.

다시 한번 확인하면 깃헙이 주는 list에서 primary이면서 verifiedemail객체를 찾아야한다.

그리고 같은 email을 가진 user가 이미 있다면 그 유저를 로그인시켜 줄거다.

나중에 이 부분에서는 계정을 생성하는걸 추가해줘야 한다.

const existingUser = await User.findOne({ email: emailObj.email });
    if (existingUser) {
      req.session.loggedIn = true;
      req.session.user = user;
      return res.redirect("/");
    } else {
    }// create an account
  } else {
    return res.redirect("/login");
  }
};

무슨 말이냐면 해당 emailuser가 없으니까 계정을 생성해야 한다는 거다.

다행히도 이미 아주 만은 데이터를 가지고 있다.

email도 있고 location도 있고 name도 있고 Github ID도 있고

username도 있다. 필요한 모든 것이 갖춰져 있다.

여태까지의 변경 사항들을 저장한 다음 테스트 해본다.

실행시켜보면 이 코드가 실행될거다.

req.session.loggedIn = true;
      req.session.user = user;
      return res.redirect("/");

왜냐하면 해당 email을 가지고 있는 user가 이미 데이터 베이스에 있고

GithubAPI에서 해당 email을 주기 때문이다.

테스트 해본다. 새로고침하고 나면 에러가 뜬다.

ReferenceError: user is not defined

user가 정의되지 않았다고 뜬다.

  const existingUser = await User.findOne({ email: emailObj.email });
    if (existingUser) {
      req.session.loggedIn = true;
      req.session.user = existingUser;

userexistingUser으로 변경해준다. 그러고 나서 다시 테스트를 해본다.

이제 로그인이 잘 된다.

이제 이 user를 지우고 "만일 계정이 없다면 어떻게 할 것인가"에 대해 해보도록 한다.

그래서 하나를 만들어야 한다. 그리고 일종의 password 같은걸 만들어야 한다.

mongodb에서 db.sessions.remove({})를 해주고 나면

이 코드는 실행 되지 않을거다.

  const existingUser = await User.findOne({ email: emailObj.email });
    if (existingUser) {
      req.session.loggedIn = true;
      req.session.user = existingUser;
      return res.redirect("/");
    } else {
      // create an account

// create an account 뭐가 실행되냐면 이게 실행될거다.

이제 user를 생성해야 한다.

await User.create({
      name,
      username,
      email,
      password,
      location,

이부분을 이용해서 사용한다. 똑같이 해보도록 한다. await User.create()user를 만들어 주고

const existingUser = await User.findOne({ email: emailObj.email });
    if (existingUser) {
      req.session.loggedIn = true;
      req.session.user = existingUser;
      return res.redirect("/");
    } else {
      const user = await User.create({
        name: userData.name,
        username: userData.login,
        email: emailObj.email,
        password: "",
        location: userData.location,
      });

그리고 나서 이제 값을 채우면 된다. nameuserData.name이다.

이 데이터는 객체이다. 그래서 userData.name이라고 해준다.

다음은 username이건 userData.login이 될거다.

emailuserData.email이 아닌 emailObj.email이다.

password는 없으니 " "으로 해준다.

location은 이미 있으니 userData.location으로 해준다.

그리고 User.js에서 하나 추가해준다.

const userSchema = new mongoose.Schema({
  githubId: { type: Number },

바로 githubId이다. typeNumber이고 required:flase, unique:true로 해준다.

그냥 number만 써준다. 이렇게 하는 이유는 userGithub로 로그인했는지 여부를 알기 위해서이다.

이건 로그인 페이지에서 유저가 email로 로그인하려는데 password가 없을때 유용할수 있다.

githubId를 체크하면 된다. 사실 githubId가 아니라 githubLoginOnly라 해준다.

아니면 noPasswordAccount 아니면 socialOnly typeBoolean으로 해준다.

defaultfalse로 해준다.

  socialOnly: { type: Boolean, default: false },

이렇게 계정을 만들어주면 이 계정은 Github을 이용해 계정을 만들었다면 password는 없게 된다.

그렇다면 usernamepassword form을 사용 할수 없다.

그래서 계정이 socialOnly=true라는걸 알려줘야 한다.

      const user = await User.create({
        name: userData.name,
        username: userData.login,
        email: emailObj.email,
        password: "",
        socialOnly: true,
        location: userData.location,
      });

이렇게 user를 생성하도록 만들었다. 여기서 User.create()는 새로 만든 userreturn시켜준다.

user를 로그인 시켜줘야 한다.

const user = await User.create({
        name: userData.name,
        username: userData.login,
        email: emailObj.email,
        password: "",
        socialOnly: true,
        location: userData.location,
      });
      req.session.loggedIn = true;
      req.session.user = user;
      return res.redirect("/");

그래서 밑에 이렇게 넣어준다. 이 부분을 다듬어 보는건 다음에 해보도록 한다.

그리고 이건 다른 옵션이다. 데이터베이스에 해당 email을 가진 user가 없을때

이렇게 password없이 Github의 데이터로 user를 생성하고

그런 user에게는 socialOnly:true값을 주고 있다.

그리고 여기 postLogin때 유용 할거다.

export const postLogin = async (req, res) => {

왜냐하면 user를 찾을때 몇몇 password들을 비교해볼텐데

그러기 위해 if else를 써야 될거 같다.

userGithub로 계정을 만들고 password로 로그인을 시도한다면

user에게 "password가 없으니 Github로 로그인"하라고 말해줘야 한다.

아니면 pasword를 새로 생성하는 페이지를 만들든지 해야 한다.

이제 테스트 해보도록 한다. 데이터베이스엔 user가 없고

이 계정은 Github데이터로만 만들어졌을거다.

 const user = await User.create({
        name: userData.name,
        username: userData.login,
        email: emailObj.email,
        password: "",
        socialOnly: true,
        location: userData.location,
      });

그리고 Github데이터는 avatarUrl이라 하는 것이 있는데 그건 나중에 써보도록 한다.

테스트를 해본다. login -> Continue with Github하면 계정이 생성되고

(해당 강의에서는 에러가 발생하는데 그냥 로그인이 잘된다.)

에러는 User 인증에 실패했습니다. User validation failed라고 뜬다.

password가 필수 조건이라고 한다.

  password: { type: String, required: false },

password required값을 false로 바꿔준다. 유일한 옵션이다.

(그냥 없애도 잘 작동 한다.)

이건 몇몇 user들에게는 password가 없을테니 그런거다.

다시 실행해 보면 잘된다. (수정을 안 한 상태에서도 잘 작동하였지만 혹시 모를 에러때문에 이렇게 수정을 하고 진행하도록 한다. )

Github으로 부터 온 프로필 이름이 나온다.

mongodb로 가서 user를 보면 socialOnly:true인 계정이 생성 되었다.

password는 없다. 왜냐하면 비어있는 해시값이기 때문이다.

usernameGithub username일 테고 emailGithub email이다.

location이런 것들 전부 Github에서 오고 있다.

profile
꿈꾸는 개발자

0개의 댓글