[Node+MongoDB]회원기능 만들기1(passport, 로그인기능)

김나나·2024년 8월 28일

Node.js

목록 보기
21/50

session방식으로 회원가입 기능을 만들어볼 것.

  1. 가입 기능
  2. 로그인 기능
  3. 로그인 완료시 세션 만들기
  4. 로그인 완료시 유저에게 입장권 보내줌
  5. 로그인여부 확인하고 싶으면 입장권 조회

✨passport 라이브러리 설치 및 셋팅

  1. 터미널 열어 npm install express-session passport passport-local 입력하여 설치

  2. 라이브러리 셋팅을 위해 서버 파일 server.js에 아래 코드 넣어주자

const session = require('express-session')
const passport = require('passport')
const LocalStrategy = require('passport-local')

app.use(passport.initialize())
app.use(session({
  secret: '암호화에 쓸 비번',
  resave : false,
  saveUninitialized : false
}))

app.use(passport.session()) 

secret은 세션의 document id는 암호화해서 유저에게 보내는 것으로 암호화에 쓸 비번을 넣는 곳
resave는 유저가 서버로 요청할 때마다 세션을 갱신할 것인지
saveUninitialized는 로그인을 하지 않아도 세션을 만들 것인지에 대한 것

라이브러리 찾아보고싶으면 express-session한 번 찾아보자.


✨로그인 기능

  1. mongoDB에 user라는 이름으로 collection하나를 생성하고

이 컬렉션에 유저의 id와 pw를 보관할 document를 만들어주면 된다.

테스트용으로 하나 만들어두자.

  1. login.ejs파일 하나 만들어서 /login접속시 로그인 페이지 보여줄 수 있도록!

참고로 input에 name속성에 username과 password라고 사용한 것은 passport 라이브러리를 사용하는 경우에는 name속성을 맞춰줘야 하기 때문이다.

  1. 이제 서버 파일로 돌아가서
app.post('/login', async (요청, 응답, next) => {
  제출한 id/pw가 DB에 있는거랑 일치하는지 확인하고 세션생성
}) 

이렇게 해주면 되는데 passport 라이브러리를 설치했으니 사용해주도록 하자..!

app.use가 많은 곳 하단쯤에 아래 코드를 복사해서 넣어준다.

passport.use(new LocalStrategy(async (입력한아이디, 입력한비번, cb) => {
  let result = await db.collection('user').findOne({ username : 입력한아이디})
  if (!result) {
    return cb(null, false, { message: '아이디 DB에 없음' })
  }
  if (result.password == 입력한비번) {
    return cb(null, result)
  } else {
    return cb(null, false, { message: '비번불일치' });
  }
}))

저 장황한 passport.use가 뭐하는 곳이냐면..

passport.use(new LocalStrategy(async (입력한아이디, 입력한비번, cb) => {
  // 제출한 아이디/비번 검사하는 코드 적는 곳
}))

검사 로직 적는 곳..!
passport.authenticate('local')()사용하면 위 기능 실행됨!

만약 id/pw 외에 다른 것도 검증하고 싶다면
passReqToCallback 옵션으로 검증 가능하니 찾아보자..!

  1. 이제 authenticate를 사용해서 로그인 버튼 누를 때 실행되도록 코드를 짜주자

    이런 식으로.. 사용할 수 있도록 좀 더 다듬어서

    이런 식으로 사용해주면 된다.

    error: 에러시
    user: 성공시 로그인한 유저 정보
    info: 로그인이 실패했을 경우

app.post("/login", async (요청, 응답, next) => {
  
  passport.authenticate('local', (error, user, info)=>{ 

    if(error) return 응답.status(500).json(error)
    if(!user) return 응답.status(401).json(info.message)
    
    // 로그인 성공
    요청.logIn(user, (err)=>{
      if (err) return next(err)
      응답.redirect('/')  // 로그인 완료시 실행할 코드
    })

   })(요청, 응답, next)

});

이까지 하고 로그인을 해보면

Error: Failed to serialize user into session

이런 오류가 나오는데, 이 부분은 세션을 만들어주면 된다.


✨serializeUser로 세션 생성

로그인하면 세션을 만들어주고,
세션 id가 담긴 쿠키를 보내주는 것을 해보자..!

  1. 간단하게 passport.serializeUser를 사용하여 세션 생성을 해주자
passport.serializeUser((user, done) => {
  process.nextTick(() => {
    done(null, 세션document에기록할내용)
  })
})

해당 코드를 사용해주면 된다.

해당 코드는 로그인이 로그인이 성공하면 실행되는 요청.logIn이 실행될때 자동으로 실행된다.

위의 요청.logIn부분~!

세션document에기록할내용에는 해당 데이터가 기록된 세션 document를 메모리(DB연결되어있으면 DB)에 발행해준다.

참고로 위에서 작성된 process.nextTick()는 node.js에서 특정 코드를 비동기적으로 처리해주고 싶을 때에 사용된다.
(위와 유사한 queueMicrotask()함수도 있다.)

  1. 로그인하면 유저 정보를 어떻게 받아오는지 우선 한 번 살펴보고 코드를 마저 완성해보면
passport.serializeUser((user, done) => {
  console.log(user);
});

여기 user를 콘솔창에 출력해보면 터미널에 뜰 것이다.

뜬다.
그럼 이제 user.username이나 id나 pw나 넣어주기 편리할 것 같다.


이렇게 넣어주고 나서는 로그인 시 세션 document를 발행해주고, 그 document의 _id를 쿠키에 적어 보낼 것.

기본적으로 document에 세션 유효기간은 작성한 날 +2주라고 하는데, 이를 변경해주기 위해서는 상단에 cookie 옵션을 수정해주면 된다.


60 * 60 * 1000은 1시간,
60 * 1000은 60초동안 유지해준다.

이까지 설정을 하고 다시 로그인을 해보면..

Error: Failed to deserialize user out of session

이번에는 deserialize가 없다고 한다.

....... 넣어주자!

passport.deserializeUser((user, done) => {
  process.nextTick(() => {
    done(null, user);
  });
});

deserialize는 유저가 보낸 쿠키를 분석해주는 역할이다.
쿠키가 이상이 없다면 현재 로그인된 유저 정보를 알려준다.

이후 다른 API에서 요청.user만 해줘도 유저 정보를 받아올 수 있게 해준다.(다만 해당 코드들 아래에 작성된 api에서만 가능)

문제점으로 세션 document에 적힌 유저정보를 그대로 요청.user에 담아주는 것인데, 정보가 시간이 지날 수록 달라질 수도 있다는 점에서 혼선이 있을 수 있어 DB조회 후에 보내주는 것이 낫다.

passport.deserializeUser(async (user, done) => {
  let result = await db.collection('user').findOne({_id : new ObjectId(user.id)})
  delete result.password
  process.nextTick(() => {
    done(null, result);
  });
});


password는 넘겨주지 않는 것이 나으니 delete처리를 해주자.
위의 코드처럼 deserialize를 사용하면 최신 유저 정보를 담을 수 있게 된다.

이제 test를 해보자!!!

그리고 로그인도 해보자..

전송을 누르고,
브라우저 개발자도구에서 Application -> Cookies선택



로그인시 발급받은 쿠키 확인 가능하면 처리가 잘 된 것!!!

이후 다시 로그인창을 들어가보면

콘솔창에 현재 로그인 되어있는 유저 정보가 찍혀야한다.

지금 상태는 DB에 연결해둔 것이 아니라 서버가 재시작되면 로그인이 풀려버릴텐데, DB 연결에 관해서는 다음 포스팅에 이어해야겠다...


✔로그인기능 만들며 알게된 것

  1. 로그인에 성공하면 세션 document를 만들어 쿠키를 유저에게 보내줘야함
    -> passport.serializeUser()쓰면 자동으로 가능
  2. 유저가 쿠키 제출시 확인해보기
    -> passport.deserializeUser()쓰면 자동으로 가능
  3. 현재 로그인된 유저 정보 출력은 요청.user
profile
10분의 정리로 10시간을 아낄 수 있다는 마음으로 글을 작성하고 있습니다💕

0개의 댓글