[회고] 신입 iOS 개발자가 되기까지 feat. 카카오 자세히보기

🛠 기타/WEB

Node.js - Passport.js 기초

inu 2021. 2. 3. 15:54
반응형

Passport.js

  • express 프레임워크 상에서 사용되는 인증 미들웨어 라이브러리이다.
  • 기본적인 인증시스템 지원과 더불어 페이스북, 구글과 같은 소셜 로그인을 할 수 있도록 도와주기 때문에 매우 편리하다.

패키지 설치

$ npm install passport
  • passport.js 패키지를 설치한다.

Strategies

  • passport.js에서는 다양한 인증방법을 'strategie' 라는 이름으로 제공한다.
  • 기본적인 사용자 ID 및 PASSWORD를 사용하는 방법부터, OAuth를 사용한 위임 인증 등 다양한 strategies가 존재한다.
  • 그중 가장 기본으로 단순히 ID와 PASSWORD를 사용한 인증방법인 local strategie를 사용해보자.
  • 물론 단순한 로그인만 사용할 것이라면 굳이 passport.js를 사용할 이유는 없다. 하지만 우선 기본 동작원리를 파악하기 위해 코드를 살펴보자.
  • 코드순서 명시를 위해 기본설정-로그인정보받기-로그인정보확인-Form 순서로 설명을 기입했지만, 실질적 구동은 Form에서 로그인정보를 전달하고 이를 로그인정보받기에서 받은다음 로그인정보확인에서 이를 확인하고, 기본설정passport.serializeUserpassport.deserializeUser가 작동하면서 req에 user정보가 생성되는 원리로 작동한다.

기본 인증시스템 (local strategie)

패키지 설치

$ npm install passport-local
  • id와 password를 사용하는 기본 인증시스템을 사용하기 위해선 passport-local 패키지가 필요하다.

기본 설정

var passport = require('passport');

app.use(passport.initialize());
app.use(passport.session());

passport.serializeUser(function(user, done) {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id, function(err, user) {
    done(err, user);
  });
});
  • passport 객체를 생성한다. (passport 객체는 내부적으로 session을 사용하기 때문에 session 활성 코드 이후에 생성해야 한다.)
  • app.use(passport.initialize()) : passport를 사용한다고 express에게 알린다.
  • app.use(passport.session()) : session을 사용하여 passport를 동작시킨다고 express에게 알린다.
  • passport.serializeUser() : 로그인에 성공했을 때 작동한다. 로그인에 성공했을 때 해당 전달받은 user정보를 기반으로 작업을 수행한다. done함수의 2번째 인자로 user의 식별자를 주고, session 데이터에 해당 정보가 저장된다.
  • passport.deserializeUser() : serializeUser가 처리된 상태에서 사용자가 여러 페이지에 방문할 때마다 실행된다. done의 두 번째 인자로 user정보 전체를 전달하고, session에 저장된 user식별자를 기반으로 그에 맞는 user를 찾아 활용하게 된다. 그렇게 식별된 user가 req.user가 된다. 해당 req의 객체는 passport를 사용했기 때문에 생성되는 객체이다. (해당 객체의 존재여부판단으로 로그인여부까지 알 수 있다.)

로그인 정보 받기

app.post('/login',
  passport.authenticate('local', { successRedirect: '/',
                                   failureRedirect: '/login',
                                   successFlash: 'Welcome!',
                                   failureFlash: true })
);
  • /login으로 접속 시 passport에서 제공하는 API가 작동한다.
  • 'local'은 Strategie의 일종으로 가장 기본적인 Strategie이다. 내부적으로는 /login으로 들어오는 ID와 Password 정보를 이용해 로그인 작업을 실행한다.
  • passport.authenticate('local') 미들웨어가 인증에 실패하면 401 Unauthorized상태로 응답하고 이후 작업(redirection)은 실행되지 않는다.
  • req.user안에는 인증된 유저에 대한 정보가 들어있다. (req.user.username 등으로 접근 가능)
  • successRedirect은 성공 시 redirection 할 위치이다.
  • failureRedirect은 실패 시 redirection 할 위치이다.
  • successFlash는 성공 시 플래시 메시지로 지정한 문자를 띄워준다.
  • failureFlash를 true로 주면, 콜백 인증이 실패한 이유를 플래시 메시지에 띄워준다. (failureFlash: 'Invalid username or password.'와 같이 직접 메시지를 지정할 수도 있다.)
  • cf. 플래시 메세지 사용을 위해서는 req.flash() 기능이 필요한데, Express 3.X 이상부터는 해당 기능을 지원하지 않는다. 따라서 추가적인 미들웨어가 필요하다. (connect-flash)

로그인 정보 확인

var LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy({
    usernameField: 'username',
    passwordField: 'password'
  },
  function(username, password, done) {
    User.findOne({ username: username }, function (err, user) {
      if (err) { return done(err); }
      if (!user) {
        return done(null, false, { message: 'Incorrect username.' });
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user);
    });
  }
));
  • usernameFieldpasswordField에 form에서 전달해줄 id와 password의 name을 입력한다. (default : username, password)
  • 위의 passport.authenticate()에서 로그인 정보를 받으면, 미들웨어로서 이를 처리하도록 하는 코드를 작성한다. (위 코드는 예시이며, 현 프로젝트 구성에 맞게 짜면 된다.)
  • done에 false 혹은 user를 전달하여 로그인 여부를 passport에게 알려주는 것이다. user를 할 경우 로그인에 성공한 것이고, false는 실패한 것이다.
  • false를 할 경우 메시지로 무엇이 틀렸는지 알려줄 수도 있다. 이는 플래시 메시지 표기에 활용될 수 있다.

Form

<form action="/login" method="post">
    <div>
        <label>Username:</label>
        <input type="text" name="username"/>
    </div>
    <div>
        <label>Password:</label>
        <input type="password" name="password"/>
    </div>
    <div>
        <input type="submit" value="Log In"/>
    </div>
</form>
  • 로그인 form은 위와 동일한 기능을 하는 형태로 구성해야 한다.
  • 이때 name값은 반드시 위에서 설정한 usernameFieldpasswordField의 값이어야 한다.

로그아웃

app.get('/logout', function(req, res){
  req.logout();
  req.session.save((err) => {
      res.redirect('/');
  });
});
  • req.logout()을 요청시 req.user 데이터가 삭제된다.
  • 다만 가끔 바로 session 처리가 바로 되지 않는 경우가 있기 때문에 req.session.destroy로 session 현재정보를 저장한뒤 redirection하는 것이 더 안전하다.

로그인

req.login(user, function(err) {
  if (err) { return next(err); }
  return res.redirect('/users/' + req.user.username);
});
  • 간단하게 로그인 작업을 처리해주는 req.login()도 존재한다.
  • passport.authenticate()는 내부적으로 req.login()를 호출한다.
  • 보통 회원가입 후 바로 로그인처리를 수행하고 싶을 때 많이 쓰인다.

cf. done의 역할

done(null, false, { message: 'Incorrect password.' })
  • return을 보조하는 역할 정도로 생각하면 된다.
  • done의 첫 번째 파라미터 : 에러 처리 시에만 사용하며, DB 조회 등에서 발생하는 서버 에러를 넣는다.
  • done의 두 번째 파라미터 : 성공할 경우의 return값
  • done의 세 번째 파라미터 : 서버 에러 없이 임의로 에러를 입력할 때 사용하는 메시지

참고 : www.passportjs.org/docs/

반응형

'🛠 기타 > WEB' 카테고리의 다른 글

JWT (JSON Web Token)  (0) 2021.02.03
서버기반 인증시스템과 토큰기반 인증 시스템  (0) 2021.02.03
Node.js - session  (0) 2021.02.02
Node.js - cookie  (0) 2021.02.02
Node.js - multer (파일 업로드)  (0) 2021.01.31