## 개요
- 회원가입과 로그인을 직접 구현할 수 있지만, 허점이 있을 수 있고 세션이나 쿠키 처리 등의 이유로 복잡하기에 미리 만들어진 검증된 모듈을 사용하는 것이 권장된다.
- Passport는 이에 적합한 미들웨어 모듈이다.
말 그대로 여권이라는 의미인데, 여권 소지자가 입출국 자격에 대해서 인증하듯이, 우리가 요청/응답을 받을 때도 이 모듈을 사용하여 인증을 받을 수 있다.
- 로컬 계정 ( 이메일/비밀번호 )부터 구글, 카카오, 네이버, 깃허브 같은 소셜 로그인까지 모두 지원된다.
- 이런 인증방식 하나하나를 전략 strategy라고 한다.
- 공식문서 : https://www.passportjs.org/
Passport.js
Simple, unobtrusive authentication for Node.js
www.passportjs.org
### 주요개념
- Strategy 전략
인증방식을 말한다.
passport-local (이메일,비번)
passport-google-oauth20 (구글)
passport-kakao (카카오)
- serializeUser / deserializeUser
로그인 성공 후에, 사용자 정보를 세션에 저장하거나 불러올 때 사용한다.
예를 들어서 db에서 꺼낸 객체 -> 세션에 id만 저장 -> 요청 들어올 때 id로 다시 user 꺼내오기
- req.login / req.logout / req.isAuthenticated
로그인, 로그아웃, 로그인 상태 확인할 때 쓰는 메서드
npm install passport passport-local express-session
### 로컬 로그인 기준 예제코드
const express = require('express');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy; // local 전략 가져오기
const session = require('express-session'); // 세션 미들웨어
const app = express();
// 미들웨어 설정
app.use(express.urlencoded({extended : false})); // form 데이터 파싱
app.use(session({secret:'secret', resave : false, saveUninitialized : false})); // 세션 설정
app.use(passport.initialize()); // pass초기화
app.use(passport.session()); // passport 세션 연결
// 사용자 db 예시 ( 실제로는 db연결 필요 )
const users = [{id : 1, username:'test', password:'1234'}];
// local 전략 정의
passport.use(new LocalStrategy((username, password, done) => {
const user = users.find(u=> u.username === username );
if(!user) return done(null, false, {message:'사용자 없음'});
if( user.password !== password ) return done(null, false, { message : '비밀번호 틀림' });
return done(null, user);
}));
// 사용자 세션 저장
passport.serializeUser((user,done) => {
done(null, user.id); // user.id만 세션에 저장
});
// 사용자 세션에서 꺼내기
passport.deserializeUser((id, done) => {
const user = users.find(u=> u.id === id);
done(null, user);
});
app.post('/login', passport.authenticate('local', {
successRedirect: '/success', // 성공 시 이동할 경로
failureRedirect : '/fail' // 실패 시 이동할 경로
}));
app.get('/success', (req, res) => res.send('로그인 성공!'));
app.get('/fail', (req, res) => res.send('로그인 실패 ㅠㅠ'));
// 서버 실행
app.listen(3000, () => console.log('서버 실행 중'));
사용자 요청이 왔을 때 처음 실행되는 부분은 '/login' 엔드포인트의 post 메서드다.
이후에 바로 passport.authenticate('local', {...}); 미들웨어가 실행된다.
### 그럼 이후에 passport.authenticate('local') 안에서는 무슨 일이 일어날까?
- 여기서 passport-local 전략이 불려서 실행된다.
- 이 전략 안에서 자동으로 req.body.username과 req.body.password를 꺼내서 가져오게 된다.
- LocalStrategy 기본 옵션이 아래와 같이 되어있기 때문이다.
usernameField:'username',
passwordField:'password'
- LocalStrategy 가 정의된 코드를 보면, 실제로는 이곳에서 db쿼리 로직이 들어가면 된다. 아래와 같은 예시를 들 수 있다.
passport.use(new LocalStrategy({
usernameField: 'id', // req.body.id 로부터 가져옴
passwordField: 'pw' // req.body.pw 로부터 가져옴
}, (username, password, done) => {
// 예: MySQL 쿼리 날리는 부분
db.query('SELECT * FROM users WHERE username = ?', [username], (err, results) => {
if (err) return done(err); // 쿼리 에러
if (results.length === 0) {
return done(null, false, { message: '사용자 없음' }); // 유저 없음
}
const user = results[0];
if (user.password !== password) {
return done(null, false, { message: '비밀번호 틀림' }); // 비번 틀림
}
return done(null, user); // 성공 → user 객체 넘김
});
}));
### 자 그럼 이런 의문이 들 수 있다. 아 그러면 passport를 사용하면 알아서 jwt 액세스 토큰부터 리프레시 토큰까지 알아서 해주는건가?..
- 결론은 그렇지 않다이다.
- passport-local 전략은 아주 단순하게
- 사용자 id/pw 받아서, db에서 확인하고, 맞으면 done(null, user) 호출, req.login()으로 세션에 user정보 저장 이게 전부다.
- 세션 기반 로그인이라서, 서버는 user 정보를 메모리나 redis 같은데 저장하고 클라이언트는 세션 쿠키 ( connect.sid )를 들고 다니면서 인증을 한다.