passport-local는 nodejs에서 로그인을 간편하게해주고, 브라우저 쿠키에 세션과 웹서버에 세션을 저장해서 Authorization(인가)를 해줄 수 있도록 도와주는 라이브러리다. passport로 로그인처리를 하는 법을 블로깅해보도록 하겠다.
"body-parser": "^1.19.2",
"cookie": "^0.4.2",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"express": "^4.17.3",
"express-session": "^1.17.2",
"install": "^0.13.0",
"nodemon": "^2.0.15",
"npm": "^8.5.1",
"passport": "^0.5.2",
"passport-local": "^1.0.0",
"passport-session": "^1.0.2",
"session-file-store": "^1.5.0"
// session-file-store는 다른 DB로 대체가능
필요한 모듈을 require해준다.
const express = require("express");
// session 사용할때 필요
const session = require('express-session');
// session을 저장할 때 필요
const FileStore = require('session-file-store')(session);
// cors 고려해서 응답시 필요
const cors = require('cors');
// 클라이언트의 쿠키를 웹서버가 파싱할 수 있도록 require
const cookieParser = require('cookie-parser');
// 클라이언트에서 post요청을 했을때 req.body로 데이터를 받을 수 있도록 require
const bodyParser = require("body-parser");
// passport와 passport-local
const passport = require('passport');
const Strategy = require('passport-local').Strategy;
const app = express();
app.use(cors({
origin: true,
credentials: true // 요청에 쿠키를 넣고싶으면 이 옵션 사용
}));
// body parse
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
// 이 세션함수는 반드시 passport.session() 전에 사용해야한다
app.use(session({
secret: 'secret key',
resave: true,
saveUninitialized: false,
secure: false,
store: new FileStore() // 세션을 저장할 store를 할당해줌
}));
// passport 초기화
app.use(passport.initialize());
app.use(passport.session());
Strategy, 전략이란 말이 어색할 것이다.
단순히 로그인을 어떻게 구현할 것이라고 전략을 세운다고 생각하면 될 것 같다.
let strategy = new Strategy({
usernameField: 'email',
passwordField: 'password',
session: true, // session에 저장 여부
passReqToCallback: true, // 이 옵션을 설정하면 아래 콜백 함수의 첫번째 파라미터로 req 객체 전달됨
}, (req, email, password, done) => {
if (email === 'test@naver.com' && password === '1234') {
let userInfo = {
email: 'test@naver.com',
name: '홍길동',
birth: '1102.05.29'
}
done(null, userInfo);
} else {
done(null, false, { message: "Incorrect ID/PW" });
}
});
passport.use(strategy);
serializeUser는 로그인 성공을 하면 세션을 저장해주는 코드이고,
deserializeUser는 세션이 있을때 세션정보를 꺼내주는 코드라고 생각하면된다.
세션이 있다면 req.user로 접근이 가능하다.
passport.serializeUser(function (user, done) {
console.log("serializeUser user : ", user);
done(null, user);
}); // 로그인 성공했을때 호출됌
passport.deserializeUser(function (user, done) {
console.log("deserializeUser user : ", user);
done(null, user); // 여기 유저는 serializeUser에서 done으로 넘겨준 user임
// 여기서 최종으로 넘기면 세션에 저장되서 req.user로 사용가능하다?
}); // 모든요청마다 호출됌
app.post('/login', (req, res, next) => {
passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/' },
(err, user, message) => {
if (user !== undefined) {
req.logIn(user, (err)=>{
if(err)return next(err);
res.json({ result: 'User have sesseion' });
});
}
}
)(req, res, next);
});
passport.authenticate의 첫번째 인자는 local전략을 사용하겠다란 말이고,
두번째 객체는 로그인 성공, 실패시 어디 Path로 갈 것인지 정하는 옵션이고,
세번째 인자인 콜백함수는 로그인성공시 serializeUser가 실행되고나서 그 유저 정보를 콜백함수 두번째 인자에서 받아볼 수 있고, 로그인 실패시 콜백함수 첫번째 인자에서 err을 받아볼 수 있다.
app.get('/logout', (req, res) => {
// console.log('/logout', req.session);
req.logOut();
res.json({ result: 'User have not sesseion' });
})
app.get('/', (req, res) => {
console.log('req.user', req.user);
res.json({ userInfo: req.user});
});
user정보를 클라이언트에서 바로 쏴서 클라이언트에서 유저정보가 없으면 Authorization을 안해줘도되고, 유저정보가 있으면 Authorizaion을 해줘도 되는 즉, Authorization처리를 클라이언트에서 해줘도 되고 다음과 같이 서버에서 해줘도 된다.
app.get('/', (req, res) => {
if(req.user === undefined){
res.status(400).send('로그인해주세요');
}else{
res.status(200).send('Authorizaion해주세요')
}
})
const express = require("express");
const session = require('express-session');
const FileStore = require('session-file-store')(session);
const cors = require('cors');
var cookieParser = require('cookie-parser');
// var cookie = require('cookie');
const bodyParser = require("body-parser");
const app = express();
// middleware list
app.use(cors({
origin: true,
credentials: true
}));
/*
Credentials(인증서) 이 있는 CORS 요청은 Client와 Server
둘다 Credentials를 사용하겠다는 속성을 설정해줘야 통신이 가능
*/
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
// 이 세션함수는 반드시 passport.session() 전에 사용해야한다
app.use(session({
secret: 'secret key',
resave: true,
saveUninitialized: false,
secure: false, // 이건 뭘까
store: new FileStore()
}));
const passport = require('passport');
const Strategy = require('passport-local').Strategy;
// passport.use(strategy); 이후에 미들웨어를 사용해야함
app.use(passport.initialize());
app.use(passport.session());
let strategy = new Strategy({
usernameField: 'email', // input name
passwordField: 'password', //input name
session: true, // session에 저장 여부
passReqToCallback: true, // 이 옵션을 설정하면 아래 콜백 함수의 첫번째 파라미터로 req 객체 전달됨
}, (req, email, password, done) => {
if (email === 'test@naver.com' && password === '1234') {
let userInfo = {
email: 'test@naver.com',
name: '홍길동',
birth: '1102.05.29'
}
done(null, userInfo);
} else {
done(null, false, { message: "Incorrect ID/PW" });
}
});
passport.use(strategy);
/*
serializeUser는 로그인 성공을 하면 세션을 저장해주는 코드이고,
deserializeUser는 세션이 있을때 세션정보를 꺼내주는 코드라고 생각하면된다.
세션이 있다면 req.user로 접근이 가능하다.
*/
passport.serializeUser(function (user, done) {
console.log("serializeUser user : ", user);
done(null, user);
}); // 로그인 성공했을때 호출됌
passport.deserializeUser(function (user, done) {
console.log("deserializeUser user : ", user);
done(null, user); // 여기 유저는 serializeUser에서 done으로 넘겨준 user임
// 여기서 최종으로 넘기면 세션에 저장되서 req.user로 사용가능하다?
}); // 모든요청마다 호출됌
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json()); // 요놈이 들어가야 한다.
app.get('/', (req, res) => {
console.log('req.user', req.user);
// passport.authenticate('local', {}, (err, user, message)=>{
// console.log(user);
// })
res.json({ userInfo: req.user});
});
// passport.authenticate를 하면 req.login()함수가 자동 실행됌
app.post('/login', (req, res, next) => {
console.log('/login', req.session);
passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/' },
(err, user, message) => {
console.log("req.user : "+ JSON.stringify(req.user));
if (user !== undefined) {
console.log('app.post : ', user);
req.logIn(user, (err)=>{
if(err)return next(err);
res.json({ result: 'User have sesseion' });
});
}
}
)(req, res, next);
});
app.get('/logout', (req, res) => {
// console.log('/logout', req.session);
req.logOut();
res.json({ result: 'User have not sesseion' });
})
app.listen(80, () => {
console.log('80포트 실행됌')
})