글에 앞서 사족
생활코딩의 Express 강의를 어느정도 필요한 부분은 완강했다고 생각한다. 여러가지 미들웨어를 사용해보았고, 이번 글에서는 Express 프레임워크의 passport 미들웨어, flash메세지에서 발생한 오류, 해결방법을 작성해보려 한다.
아마 나와 같은 강의를 시청한 분이 이 코드를 본다면 조금 다를 수도 있는데, 성공시 flash 메세지 기능은 추가하지 않았고, lowDB대신 MySQL 을 사용했기에, 그 부분에서 차이가 있을 수 있다.
const db = require('../lib/db.js');
module.exports = function(app){
const passport = require('passport'),
LocalStrategy = require('passport-local').Strategy;
const flash = require('connect-flash');
app.use(passport.initialize()); // 패스포트 사용
app.use(passport.session()); // 패스포트와 세션 연결?
app.use(flash());
passport.serializeUser(function(user, done){ // 로그인 성공시 호출, 세션에 값을 추가.
return done(null, user.id);
});
passport.deserializeUser(function(id, done){ // 위의 함수로 인해 세션에 값이 추가된 이후 계속 호출
return db.query('SELECT * FROM users WHERE id=?',[id],(err, result)=>{
if (err) throw err;
return done(null, result[0]);
});
//done(null, authData); // authData를 아규먼트로 전달해서 req.user 객체로 사용가능
});
passport.use(new LocalStrategy({
usernameField: 'email', // 기본값 username, 바꾸고싶다면 첫번째 파라미터로 객체
passwordField: 'password' // 기본값 password 그대로 써도 상관없으면 바로 함수
},
function (email, password, done) {
db.query(`SELECT * FROM users WHERE email=?`,[email], (err, result)=>{
if (err) throw err;
if (!result[0]){
//console.log('email not found');
return done(null, false, {message: '이메일이 존재하지 않습니다.'}); // 들어가기 전에 리다이렉트됨 // 커스텀으로 해결
}
if (password !== result[0].password){
//console.log('pw not found');
return done(null, false, {message: '패스워드가 일치하지 않습니다.'});
}
return done(null, result[0]);
});
return;
}
));
return passport;
}
문제에 앞서 본인의 passport 미들웨어 관리코드. 학습하면서 여러 주석처리를 한 코드를 그대로 긁어온 것이다. 밑에서 따로 코드들 이미지로 보면서 진행할 것이기에 사실 안봐도 된다.
// 문제 발생
위의 코드를 입력 후,
위 주소로 로그인 정보를 넘겨 로그인 시도시, (1번 주소 기억하자)
해당 함수로 로그인 정보를 확인, 로그인 실패시 1번 또는 2번의 메세지를 session에 flash오브젝트에 추가,
전 코드의 1번 주소로 리다이렉트로 보내지며,
위 코드의 1번 으로 인해 session에 저장되어있던 flash오브젝트의 메세지를 가져와,
2번의 feedback 변수로서 화면에 보여져야 하는데, flash 메세지가 표시되질 않았다.
분명 강의에서는 제대로 되던데.
무엇이 문제인지 확인을 해보았고, 원인은 session의 flash오브젝트에 값이 저장이 되지않고있었다.
session의 값이 저장되기전에 리다이렉트되는 문제는 강의중에 다루어졌었고, 그때는 session의 save함수로 해결했었다.
나는 해당 지식을 살려 어떻게든 리다이렉트 되기 전에 save함수를 사용하고 싶었으나, 로그인 시도시에 사용되는 passport의 authenticate함수는 request 와 response 를 파라미터로 받지 않았기에 어떻게 save함수를 끼워넣어야 할지
막막했다.
// 문제 해결
나는 구글에 최대한 핵심적인 단어만 골라 ' passport flash massage session save ' 라는 문장으로 검색을 했다.
그리고 나는 나에게 필요한 검색결과를 찾아냈다.
해당 코드는 authenticate 의 커스텀 콜백 함수이다.
기존에 쓰던 익숙한 request, response, next를 인자로 받는 콜백 함수에서,
passport.authenticate 함수를 위와 같은 형식을 맞춰서 // ('local', (err, user, info)=>{})(req, res, next) -이렇게
그 안에 콜백 함수를 작성하면 된다.
우리는 실패시의 상황에 해당 함수가 어떻게 동작하는지 간략하게 생각해보자.
일단 authenticate 함수의 첫 인자로 똑같이 local을 받는 것을 보면, 밑의 코드인 local strategy 가 실행될것임을
짐작해 볼 수 있다.
그리고 해당코드의 리턴값의 done 함수는 2개에서 3개의 프로퍼티를 주고있다.
첫번째 값은 null
두번째 값은 성공시 오브젝트, 실패시 false
세번째 값은 session의 flash오브젝트에 들어가야 할 메세지 변수.
자 그리고 이걸 다시 보자.
우리가 봐야할건 authenticate 의 콜백 함수에서 받는 err, user, info 파라미터.
console.log로 찍어보면 알겠지만, user 값은 로그인 성공시 오브젝트값을, 실패시 false를 뱉고,
info값은 실패시 출력이 되어야했던 flash 메세지 값이 들어가 있는걸 볼 수 있다.
위의 done 함수의 프로퍼티와 자리가 완벽히 일치하며, done의 첫번째 프로퍼티인 null값은
authenticate 의 첫번째 파라미터인 err의 값이라는걸 유추할 수 있다.
이렇게 우리는 실패하면 user가 false값으로 오는 점을 알기에 실패했을 시의 조건문을 작성할 수 있게됬으며,
이후 flash함수로 직접 flash 메세지 값을 넣고,
/* info를 바로 넣어보았는데 원하는 대로 작동하지 않았다. flash(변수이름, 변수값) 형식을 지켜야 하나보다. */
이후 session.save함수를 실행, 콜백으로 리다이렉트를 걸어주면, session에 flash값이 제대로 저장되고
원하는 결과를 마침내 볼 수 있게 되었다.
이외에 그 밑에있는 login함수를 통해서 로그인 성공시(user값이 있을시) 어떻게 동작하는지도 볼 수 있으며, 로그인 도중 req를 호출할 일이 있으면 해당 함수에서 지지고 볶고 하면 되지 않을까 싶다.
끝으로 사족 및 일정
위에 작성한 내용 중 done함수가 authenticate 함수와 연결된다 등의 유추했다, 생각한다, 짐작한다 등의 정보는 정확한 정보가 아닌 본인의 뇌피셜이니 너무 맹신하지는 말았으면 한다. 팩트체크를 하고 싶지만, 배울것도 많고, 영어도 그다지 잘하지않기에 그럴 시간이 안된다.
원래는 오늘 알고리즘 문제풀이를 올려볼까 했는데, 알고리즘 문제풀이는 푸는 과정을 녹화 후 편집, 유튜브에 올리는 방식으로 진행할까 생각중이다.
다음주에 토이프로젝트(아마도 게시판) 시작하고, 그것이 끝나면 드디어 스프링 프레임워크를 배워보려고 한다.
여태껏 배워놓은 node.js에서 학습한 내용들이 도움이 되었으면 한다.
'프로젝트' 카테고리의 다른 글
Node.js - 게시판 ( 게시물 및 댓글 작성 / 삭제 ) (0) | 2022.09.07 |
---|---|
Node.js - 게시판 ( 작성 / 수정 / 삭제 ) (0) | 2022.09.05 |
Node.js - 게시판 ( 로그인 ) (0) | 2022.09.05 |
Node.js - 게시판 ( 메인페이지 ) (0) | 2022.09.04 |
Node.js - 로그인 기능 구현 (0) | 2022.08.21 |