[엘리스 SW트랙 4기] 7주차 - Day 33: Express.js와 MongoDB로 웹서비스 만들기(2)

랸나·2023년 4월 12일
0
오늘 역대급으로 집중 못하고 이해도 못했다..
무기력하고 피곤하고 머리도 안돌아감 ㅠ 거의 아무것도 학습 못한 하루..
텁텁한 황사날씨때문인가... 환기도 못하고 답답해 죽겠다. 
숨도 잘 안쉬어지는 느낌

어제까지는 뭔가 머리가 팽팽 돌아가서 와 나 백엔드 좋아하나? 싶었는데
passport 나오니깐 다시 진흙에 빠진 느낌...... 처음으로 돌아간 기분이다.

1. 회원가입 구현하기

구현할 것

  • 이메일, 이름, 패스워드
  • 이메일 형식 확인
  • 비밀번호 최소 길이 확인
  • 패스워드와 패스워드 확인 문자가 일치하는지 확인
    -> 관리자가 회원의 비밀번호를 모르게 저장하는 방법은?
    -> Hash

Hash

  • 문자열을 되돌릴 수 없는 방식으로 암호화 하는 방법
    -> hash 출력값을 이용해 사용자의 비밀번호를 알아낼 수 없음.
  • 비밀번호의 Hash 값을 데이터베이스에 저장하고, 로그인 시 전달된 비밀번호를 Hash 하여 저장된 값과 비교해 로그인을 처리
  • SHA1
// crypto모듈을 사용하여 hash 값 얻음
// sha1 말고 sha224, sha256 알고리즘도 사용 가능
const hash = crypto.createHash('sha1');
hash.update(password);
hash.digest("hex")

회원가입 구현하기

  1. 회원가입 페이지 구현
  2. script를 이용해 이메일 형식, 비밀번호 확인 문자 확인
  3. form을 이용해 post 요청 전송
  4. 회원가입 처리 및 redirect

2. Passport.js와 로그인

Passport.js란?

  • Express.js어플리케이션에 간단하게 사용자 인증 기능을 구현하게 도와주는 패키지.
  • 유저 세션 관리 및 다양한 로그인 방식 추가 가능

passport-local

passport-local

  • passport는 다양한 로그인 방식을 구현하기 위해 strategy라는 인터페이스를 제공
  • strategy 인터페이스에 맞게 설계된 다양한 구현체들이 있음 (facebook, google, ...)
  • passport-local은 username, password를 사용하는 로그인의 구현체
const config = {
	usernameField: 'email',
    passwordField: 'password',
} ;
//아이디 패스워드 필드 설정 필수!

const local = new LocalStrategy(config, async (email, password, done) => {
	try{
      const user = await User.findOne({ email });
      if (!user) {
      	throw new Error('회원을 찾을 수 없습니다.');
      }
      if (user.password !== password) {
      	throw new Error('비밀번호가 일치하지 않습니다.');
      } // 이때, hashpassword를 사용해야 함
      done (null, {
      	shortId: user.shortId,
        email: user.email,
        name: user.name,
      }); // done 콜백 
    } catch(err) {
      done(err, null);
    }
})

passport.use

  • 작성한 strategy를 passport.use를 이용해 사용하도록 선언해야 함.
  • passport.use를 이용해 strategy를 사용하도록 선언한 후, passport.authenticate를 사용해 해당 strategy를 이용해 요청을 처리할 수 있음
const local = require('./strategies/local')
passport.use(local);

passport.authenticate

  • passport.authenticate 함수를 http 라우팅에 연결하면 passport가 자동으로 해당하는 strategy를 사용하는 request handler를 자동 생성
  • express-session과 passport.session()을 사용하면 passport가 로그인 시 유저 정보를 세션에 저장하고 가져오는 동작을 자동으로 수행해 줌.
--- routes/auth.js ---
router.post('/', passport.authenticate('local');
---app.js ---
const session = require('express-session'); // express가 session을 사용할 수 있도록 선언
app.use(session({
  secret: 'secret',
  resave: false,
  saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session()); // passport가 session을 사용할 수 있도록 선언해주는 부분
app.use('/auth', authRouter);

세션 유저 활용하기

  • serializeUser 와 deserializeUser를 설정해주어야 함.
  • 세션에 user 정보를 변환하여 저장하고 가져오는 기능을 제공
  • ex) 회원 id만 세션에 저장하고, 사용 시 회원 정보를 디비에서 찾아서 사용.
  • 세션 사용 시 위 두 함수를 작성 하지 않으면 passport로그인 작동 안함.
passport.serializeUser((user, callback) => {
	callback(null, user);
});

passport.deserializeUser((obj, callback) => {
	callback(null, obj);
})

로그아웃

  • passport는 req.logout 함수를 통해 세션의 로그인 정보를 삭제하여, 로그아웃 기능을 구현할 수 있음.
router.get('/logout', ...{
	req.logout();
	res.redirect('/');
})

로그인 확인 미들웨어

function loginRequired(req, res, next){
	if( !req.user) {
    	res.redirect('/');
        return;
    }
    next();
}

app.use('/posts', loginRequired, postsRouter);

3. Session Store

Session 이란?

  • 웹 서버가 클라이언트의 정보를 클라이언트별로 구분하여 서버에 저장하고 클라이언트 요청 시 Session ID를 사용하여 클라이언트의 정보를 다시 확인하는 기술
    클라이언트가 정보를 저장하고, 요청 시 정보를 보내는 Cookie와 대조됨

Session의 작동 방식

  • 서버 : 세션 생성 > 세션의 구분자인 Session ID를 클라이언트에게 전달
  • 클라이언트 : 요청 시 session id를 함께 요청에 담아서 전송
  • 서버 : 전달받은 session id로 해당하는 세션을 찾아 클라이언트 정보를 확인

Session Store를 사용하는 이유

  • express-session 패키지는 session을 기본적으로 메모리에 저장함.
    -> 현재 구현된 어플리케이션을 종료 후 다시 실행하면 모든 유저의 로그인이 해제됨.
  • 혹은 서버가 여러 대가 있을 경우, 서버 간 세션 정보를 공유할 수 없음
    -> Session Store 사용
  • 이미지 출처 : 엘리스 SW엔지니어트랙

MongoDB Session Store로 사용하기

  • connect-mongo 패키지를 이용해 MongoDB를 session store로 사용할 수 있음.
  • connect-mongo패키지는 express-session 패키지의 옵션으로 전달 가능
  • 자동으로 session 값이 변경될 때 Update되고, session이 호출될 때 find함

connect-mongo

  • connect-mongo 패키지를 사용해 express-session 설정 시 store옵션에 전달하고 monogoUrl을 설정
  • 세션 데이터를 몽고디비에 저장하고 관리하는 기능을 자동으로 수행
const MongoStore = 
      require('connect-mongo');
app.use(session({
	secret: 'SeVrEt',
    resave: false.
    saveUninitialized: true,
    store:MongoStore.create({ mongoUrl: 'mongoUrl' ,}),
}));

4. 회원과 게시글의 연동

기능

게시물 작성 시 로그인 된 회원 정보를 작성자로 추가 : 게시글 - 작성자는 populate하여 사용하도록 구현

author: {
  type: Schema.Types.ObjectId,
  ref: 'User'
  required: true,
}
  • 게시글 수정, 삭제 시 로그인된 유저와 작성자가 일치하는지 확인
  • 작성자의 게시글 모아 보기 기능 구현

5. CSR로 댓글기능 구현하기

  1. 페이지 로드 시 필요한 리소스를 클라이언트에 선언
  2. 클라이언트에서 필요한 데이터를 비동기 호출
  3. 클라이언트가 전달받은 데이터를 가공, 리소스를 사용하여 화면에 표시

HTML Template

6. MongoDB Aggregation

Aggregation이란?

  • MongoDB에서 Document들을 가공하고, 연산하는 기능

  • RDBMS에서 SQL로 수행할 수 있는 기능들을 유사하게 구현할 수 있음.
    ex) SQL의 GROUP BY, DISTINCT, COUNT, JOIN 등

  • MongoDB의 find 는 검색 필터링과 정렬 외의 기능을 제공하지 않음.

  • 다른 Collection에서 데이터를 가져오거나, 검색된 데이터를 그룹화 하는 등의 작업이 필요한 경우 Aggregation을 통해 수행 가능

//aggregation은 Stage들의 배열로 이루어지고 각 Stage는 순차적으로 실행됨
db.posts.aggregate([
	{ $group: { _id: '$author', count:{ $sum:1}}},
    { $match: {sum: {$gt: 10}}},
    { $lookup: {from:'users', localField: '_id', foreignField: '_id', as: 'users'}},
]);
profile
백엔드개발자

0개의 댓글