익명의 개발노트

10.[인증모듈] 로그인, 회원가입, 로그아웃 구현(Passport.js) 본문

프로그래밍/NodeJS

10.[인증모듈] 로그인, 회원가입, 로그아웃 구현(Passport.js)

캡틴.JS 2019. 6. 29. 19:36
반응형

Node JS에는 인증 관련 모듈인 Passport가 있다.

통상 passport, passport-local, express-session, flash 를 한 셋트로 사용한다.

npm install passport passport-local express-session connect-flash --save

1. passport는 인증관련된 모듈을 처리

2. passport-local 은 페이스북이나 트위터 같은 소셜 로그인 말고 일반 로그인을 처리한다.

3. session은 session 관련된 부분 처리해준다.

4. flash는 에러 메세지를 Redirect하는 과정에서 쉽게 전달해주는 모듈이다. 

동작원리는 passport를 이용해서 인증처리를 실행하는 LocalStrategy를 작성하고, 여기서 작성된 값을 

serializeUser를 통해 session에 정보를 저장 후 페이지 요청시 deserializeUser를 통해 세션에서 값을 뽑아 페이지로

전달하는데, 페이지로 전달시 AJax를 통해 JSON 형태로 응답을 해줄때 커스텀 콜백을 사용한다. 

사용방법.

적용할 곳(통상 라우터 분기하는 곳 최상단(app.js), 로그인, 회원가입 부분)에 import한다.

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var session = require('express-session');
var flash = require('connect-flash');


//이 부분은 app.js에만 한다.
----------------------------- 여기부터 ------------------------------------
//passport설정은 라우터 전에 셋팅을 해준다.
app.use(session({
    secret : 'keyboard cat', //세션암호화에 대한 키값설정. 아무거나 쓰면됨.
    resave : false,
    saveUninitialized : true,
}))
//셋팅완료.
app.use(passport.initialize()); //passport 초기화
app.use(passport.session());
app.use(flash());
------------------------------ 여기까지 ----------------------------------

app.use(router);   //<- 기존에 작성한 라우터

passport를 이용한 회원가입(템플릿 엔진을 이용하여, ejs를 사용하였음)

//join.js

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var session = require('express-session');
var flash = require('connect-flash');

(...중략)


//라우터 처리  
router.get('/', (req, res)=>{
    console.log('get join url');//로그인 인증 실패시 다시 이리로 들어옴.
    var msg;
    var errMsg = req.flash('error');
    if(errMsg) msg = errMsg;
    res.render('join.ejs',{'message' : msg})   
});

//serialize 처리 해주어야함.(세션에 넣어줘야함) 
passport.serializeUser(function(user, done){
  console.log('passport session save : ', user.id)
  done(null, user.id);
});

//요청시 세션값 뽑아서 페이지 전달 
passport.deserializeUser(function(id, done){
  console.log('passport session get id : ', id)
  done(null, id);
})

//strategy를 등록, 실질적인 로직처리는 여기에.
//인증처리는 실제여기서. db 조회 로직 여기다가 작성하고, 밑에 post로 들어오면 여기서 체크하는 것임.
passport.use('local-join', new LocalStrategy({
    usernameField : 'email',
    passwordField : 'password',
    passReqToCallback : true
    }, function(req, email, password, done){
    //인증처리부분 작성  (회원가입처리였음.. ver2)
    //console.log('local-join callback called');
      var query = connection.query('select * from user where email=?', [email], function(err,rows){
        if(err) return done(err);
        if(rows.length){
            console.log('exsited user');
            return done(null, false, {message : 'your email is already used'})
        }else{
         //id없으면 회원가입
          var sql = {email : email, name: "jinse", password : password};
          var query = connection.query('insert into user set ?', sql, function(err, rows){
            if(err) throw err;
            return done(null, {'email' : email, 'id' : rows.insertId}); //세션에 담을 정보.
          })
        }
      })    
    } 
));

//이게 동작하면 authenticate() 메서드 실행되고 이 값처리는 위의 passport부분에서 실행한다.
router.post('/',passport.authenticate('local-join',{
    successRedirect : '/main',  //인증성공시 이동하는화면주소
    failureRedirect : '/join',  //인증실패시 이동하는화면주소
    failureFlash : true   //passport 인증하는 과정에서 오류발생시 플래시 메시지가 오류로 전달됨.
}));

passport를 이용한 로그인처리

var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var session = require('express-session');
var flash = require('connect-flash');


(...중략)

//라우터 처리  
router.get('/', (req, res)=>{
    console.log('get login url');//로그인 인증 실패시 다시 이리로 들어옴.
    var msg;
    var errMsg = req.flash('error');
    if(errMsg) msg = errMsg;
    res.render('login.ejs',{'message' : msg})   
});

//serialize 처리 해주어야함.(세션에 넣어줘야함) 
passport.serializeUser(function(user, done){
  console.log('passport session save : ', user.id)
  done(null, user.id);
});

//요청시 세션값 뽑아서 페이지 전달 
passport.deserializeUser(function(id, done){
  console.log('passport session get id : ', id)
  done(null, id);
})


//strategy를 등록, 이걸 사용하기 위해서 등록한 거임.
//인증처리는 실제여기서. db 조회 로직 여기다가 작성하고, 밑에 post로 들어오면 여기서 체크하는 것임.
passport.use('local-login', new LocalStrategy({
    usernameField : 'email',
    passwordField : 'password',
    passReqToCallback : true
    }, function(req, email, password, done){
       //로그인 인증처리
      var query = connection.query('select * from user where email=?', [email], function(err,rows){
        if(err) return done(err);
        if(rows.length){          
            return done(null, {'email': email, 'id' : rows[0].id})
        }else{
            return done(null, false, {'message' : 'your Login info is not found >.<'}); //세션에 담을 정보.
        }
      })    
    } 
));

//커스텀 콜백사용할 예정(ajax니깐 json 응답을 줘야하기때문에 커스텀 콜백사용)
router.post('/',function(req, res, next){
    console.log("커스텀 콜백");
    passport.authenticate('local-login', function(err, user, info){
        if(err) res.status(500).json(err);
        if(!user) return res.status(401).json(info.message)

       // req.login을 이용해서 serialize 기능이 자연스럽게 이어지도록 되어있음.
       req.logIn(user, function(err){
           if(err) {return next(err);}
           return res.json(user);
       });
    })(req, res, next); //authenticate 반환 메서드에 이 인자를 넣어서 처리해야함.
});

//main.js

//기존 app.js에서 작성된 라우터를 모듈로 뻄..
var express = require('express');
var app = express();
var router = express.Router();   //라우터 메소드 이용.
var path = require('path');  //상대경로 편하기 작성하기 위해서 쓰는 모듈


//메인페이지는 세션 정보가 있을때만 접근이 가능하게.
router.get('/', (req, res)=>{  //app.js의 app.use("/main", main);과 주소값이 겹치므로. 여기값을 수정.  router.get~ 으로 시작. 앞에 app아님!!
    //res.send("메인화면");
    console.log("잘나와", req.user)  //req.user serialize하면 id값이 req.user에 저장됨. 공식문서 참조.
    // res.sendFile(path.join(__dirname,"../public/main.html"));  //join을 이용하여 사용,  res.sendFile(__dirname + "../public/main.html"); 
    var id = req.user;
    if(!id) res.render('login.ejs');
    res.render('main.ejs', {'id':id})
});

module.exports = router;  //모듈 만든거임.

로그인을 하면 메인 페이지로 이동한다.

메인페이지에서 로그아웃 버튼을 누르면 로그인화면으로 이동하는데, 아직 세션이 끊어지지 않아서, url에 /main을 치면 

로그인 한 화면이 그대로 나온다.

따라서, 세션을 끊어주어야 한다,

세션을 끊기위해서는 공식문서에 아주 간단하게 나와있다.(나는 라우터를 사용하였기에 app.get이 아니고 router.get으로 작성)

var express = require('express');
var app = express();
var router = express.Router();   //라우터 메소드 이용.

router.get('/', function(req, res){
    console.log("logout router");
    req.logout();   //이거부르면 그냥 로그아웃되며 세션도 끊어줌.
    res.redirect('/login');
});

module.exports = router;

참고자료

1) https://github.com/wonism/TIL/tree/master/back-end/nodejs/passport-example 

2) http://www.passportjs.org/

반응형
Comments