1. serializeUser
: 사용자 정보 객체를 세션에 아이디(객체)로 저장
passport.serializeUser((user, done) => {
//done(null, user); // id만 세션에 저장
done(null, user; // user 객체 세션에 저장
});
2. deserializeUser
: 세션에 저장한 아이디(객체)를 통해서 사용자 정보 객체를 불러옴
passport.deserializeUser((user, done) => {
console.log('deserializeUser() 호출!', user);
done(null, user);
});
3. passport.session() 미들웨어가 메소드를 호출
조회한 정보를 req.user 저장
4. [저번 수업시간에 마무리 못한 부분 완료] passport 모듈을 이용한 로컬 회원가입, 로그인
** /config/passport.js
const local_signup = require('./passport/local_signup');
const local_login = require('./passport/local_login');
module.exports = function(app, passport) {
console.log('config/passport 호출!');
passport.serializeUser((user, done) => {
console.log('serializeUser() 호출!', user);
done(null, user);
});
passport.deserializeUser((user, done) => {
console.log('deserializeUser() 호출!', user);
done(null, user);
});
passport.use('local-signup', local_signup);
passport.use('local-login', local_login);
}
** passport.js
const express = require('express');
const bodyParser = require('body-parser');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const expressSession = require('express-session');
const passport = require('passport'); // npm i passport
const static = require('serve-static');
const path = require('path');
const expressErrorHandler = require('express-error-handler'); // npm i express-error-handler
const app = express();
const router = express.Router();
app.use(cookieParser());
app.use(expressSession({
secret: '!@#$%^&^*&(',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60 * 60 * 1000 }
}));
app.use(logger('dev'));
// passport의 세션을 사용하려면 그 전에 express의 세션을 사용하는 코드가 먼저 나와야 한다.
app.use(passport.initialize()); // passport 초기화
app.use(passport.session());
app.use(bodyParser.urlencoded({extended: false}));
app.use('/public', static(path.join(__dirname, "public")));
app.use('/', router);
const errerHandler = expressErrorHandler({
static: {
'404': './public/404.html'
}
});
app.use(expressErrorHandler.httpError(404));
app.use(errerHandler);
app.set('views', __dirname + "/views");
app.set('view engine', 'ejs');
const config = require('./config/config');
const database = require('./database/database');
const configPassport = require('./config/passport');
configPassport(app, passport);
const userPassport = require('./routes/route_member');
userPassport(router, passport);
app.listen(config.server_port, () => {
console.log(`${config.server_port} 포트로 서버 실행 중...`);
database.init(app, config);
});
** /routes/route_member.js
module.exports = function(router, passport) {
console.log('route_member 호출!');
router.route('/').get((req, res) => {
res.render('index.ejs');
});
router.route('/login').get((req, res) => {
res.render('login.ejs');
});
router.route('/signup').get((req, res) => {
res.render('signup.ejs');
});
router.route('/signup').post(passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true
}));
router.route('/login').post(passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login',
failureRedirect: true
}));
router.route('/profile').get((req, res) => {
if(!req.user) {
console.log('사용자 인증이 안된 상태!');
res.redirect('/');
return;
}
console.log('사용자 인증 상태!')
if(Array.isArray(req.user)) {
res.render('profile.ejs', {user: req.user[0]});
} else {
res.render('profile.ejs', {user: req.user});
}
});
}
** /views/index.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>메인</title>
</head>
<body>
<h2>메인</h2>
<p>안녕하세요. passport 테스트 페이지에 오신 것을 환영합니다.</p>
<p><a href='/login'>로그인</a> | <a href="/signup">회원가입</a></p>
</body>
</html>
** /views/login.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>로그인</title>
</head>
<body>
<h2>로그인</h2>
<form action='/login' method="post">
<p><label>아이디 : <input type="text" name="userid"></label></p>
<p><label>비밀번호 : <input type="password" name="userpw"></label></p>
<p><button type="submit">로그인</button></p>
<p>계정이 없으신가요? <a href="/signup">회원가입</a> | <a href="/">메인으로</a></p>
</form>
</body>
</html>
** /views/signup.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>회원가입</title>
</head>
<body>
<h2>회원가입</h2>
<form action='/signup' method="post">
<p><label>아이디 : <input type="text" name="userid"></label></p>
<p><label>비밀번호 : <input type="password" name="userpw"></label></p>
<p><label>이름 : <input type="text" name="name"></label></p>
<p><label>나이 : <input type="text" name="age"></label></p>
<p><button type="submit">완료</button></p>
<p>이미 계정이 있으신가요? <a href="/login">로그인</a> | <a href="/">메인으로</a></p>
</form>
</body>
</html>
** /views/profile.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>프로필</title>
</head>
<body>
<h2>프로필</h2>
<hr/>
<p>아이디 : <%=user.userid%></p>
<p>이름 : <%=user.name%></p>
<p>나이 : <%=user.age%></p>
<p><a href="/logout">로그아웃</a></p>
</body>
</html>
5. passport 모듈을 이용한 페이스북 회원가입, 로그인
** /views/login.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>로그인</title>
</head>
<body>
<h2>로그인</h2>
<form action='/login' method="post">
<p><label>아이디 : <input type="text" name="userid"></label></p>
<p><label>비밀번호 : <input type="password" name="userpw"></label></p>
<p><button type="submit">로그인</button></p>
<p>계정이 없으신가요? <a href="/signup">회원가입</a> | <a href="/">메인으로</a></p>
</form>
<p><a href="/auth/facebook">페이스북 로그인</a></p>
</body>
</html>
** /routes/route_member.js
module.exports = function(router, passport) {
console.log('route_member 호출!');
router.route('/').get((req, res) => {
res.render('index.ejs');
});
router.route('/login').get((req, res) => {
res.render('login.ejs');
});
router.route('/signup').get((req, res) => {
res.render('signup.ejs');
});
router.route('/signup').post(passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true
}));
router.route('/login').post(passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login',
failureRedirect: true
}));
router.route('/profile').get((req, res) => {
if(!req.user) {
console.log('사용자 인증이 안된 상태!');
res.redirect('/');
return;
}
console.log('사용자 인증 상태!')
if(Array.isArray(req.user)) {
res.render('profile.ejs', {user: req.user[0]});
} else {
res.render('profile.ejs', {user: req.user});
}
});
router.route('/auth/facebook').get(passport.authenticate('facebook', {
scope: ['public_profile', 'email']
}));
router.route('/auth/facebook/callback').get(passport.authenticate('facebook', {
successRedirect: '/profile',
failureRedirect: '/'
}));
}
** /config/passport.js
const local_signup = require('./passport/local_signup');
const local_login = require('./passport/local_login');
const facebook = require('./passport/facebook');
module.exports = function(app, passport) {
console.log('config/passport 호출!');
passport.serializeUser((user, done) => {
console.log('serializeUser() 호출!', user);
done(null, user);
});
passport.deserializeUser((user, done) => {
console.log('deserializeUser() 호출!', user);
done(null, user);
});
passport.use('local-signup', local_signup);
passport.use('local-login', local_login);
passport.use('facebook', facebook(app, passport));
}
** /config/passport/facebook.js
const FacebookStrategy = require('passport-facebook').Strategy; // npm i passport-facebook
const config = require('../config');
module.exports = function(app, passport) {
return new FacebookStrategy({
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.callbackURL,
profileFields: ['id', 'displayName', 'name', 'gender', 'picture.type(large)', 'email']},
(accessToken, refreshToken, profile, done) => {
console.log('passport의 facebook 호출');
console.dir(profile);
let database = app.get('database');
database.MemberModel.findOne({userid: profile.id}, (err, user) => {
if(err) return done(err);
if(!user) {
const user = new database.MemberModel({
name: profile.displayName,
userid: profile.id,
provider: 'facebook',
authToken: accessToken,
facebook: profile._json
});
user.save((err) => {
if(err) throw err;
return done(null, user);
});
} else {
return done(null, user);
}
});
});
}
** /views/profile.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>프로필</title>
</head>
<body>
<h2>프로필</h2>
<hr/>
<p>아이디 : <%=user.userid%></p>
<p>이름 : <%=user.name%></p>
<%
if(user.provider == 'facebook') {
%>
<p>이메일 : <%=user.facebook.email%></p>
<%
} else {
%>
<p>나이 : <%=user.age%></p>
<%
}
%>
<p><a href="/logout">로그아웃</a></p>
</body>
</html>
6. 로그아웃
** /routes/route_member.js
module.exports = function(router, passport) {
console.log('route_member 호출!');
router.route('/').get((req, res) => {
res.render('index.ejs');
});
router.route('/login').get((req, res) => {
res.render('login.ejs');
});
router.route('/signup').get((req, res) => {
res.render('signup.ejs');
});
router.route('/signup').post(passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true
}));
router.route('/login').post(passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login',
failureRedirect: true
}));
router.route('/profile').get((req, res) => {
if(!req.user) {
console.log('사용자 인증이 안된 상태!');
res.redirect('/');
return;
}
console.log('사용자 인증 상태!')
if(Array.isArray(req.user)) {
res.render('profile.ejs', {user: req.user[0]});
} else {
res.render('profile.ejs', {user: req.user});
}
});
router.route('/auth/facebook').get(passport.authenticate('facebook', {
scope: ['public_profile', 'email']
}));
router.route('/auth/facebook/callback').get(passport.authenticate('facebook', {
successRedirect: '/profile',
failureRedirect: '/'
}));
router.route('/logout').get((req, res) => {
req.logout();
res.redirect('/');
});
}
7. socket.io 모듈
: 웹소켓을 이용하면 클라이언트에 실시간으로 데이터를 전송할 수 있다.
socket을 구현하는 것으로 WebSocket 개발을 쉽게 하기 위한 방법이다.
클라이언트에서 EventListener로 새로운 정보를 받아 데이터를 업데이트한다.
8. socket.io으로 할 수 있는 것
① 실시간 데이터 처리
② 메세징 서비스
③ 바이너리 스트리밍, 문서 공동작업 등
9. 여러 개의 클라이언트를 서버로 접속하게 하기 위한 방법
① cors 모듈(socket.io 적용 안함, ajax로 변환)
② package.json에 proxy 설정
10. socket.io 서버 추가(아까 작업한 거 config, database, public, routes, views, package.json 가져오기)
** 1_socket_io.js
const express = require('express');
const bodyParser = require('body-parser');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const expressSession = require('express-session');
const passport = require('passport');
const static = require('serve-static');
const path = require('path');
const expressErrorHandler = require('express-error-handler');
const socketio = require('socket.io'); // npm i socket.io
const cors = require('cors'); // npm i cors
const app = express();
const router = express.Router();
app.use(cookieParser());
app.use(expressSession({
secret: '!@#$%^&^*&(',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60 * 60 * 1000 }
}));
app.use(logger('dev'));
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.urlencoded({extended: false}));
app.use('/public', static(path.join(__dirname, "public")));
app.use('/', router);
const errerHandler = expressErrorHandler({
static: {
'404': './public/404.html'
}
});
app.use(expressErrorHandler.httpError(404));
app.use(errerHandler);
app.set('views', __dirname + "/views");
app.set('view engine', 'ejs');
const config = require('./config/config');
const database = require('./database/database');
const configPassport = require('./config/passport');
configPassport(app, passport);
const userPassport = require('./routes/route_member');
userPassport(router, passport);
const server = app.listen(config.server_port, () => {
console.log(`${config.server_port} 포트로 웹 서버 실행중...`);
database.init(app, config);
});
const io = socketio(server);
console.log('socket.io 서버 준비 완료!');
io.sockets.on('connection', (socket) => {
console.dir(`connection : ${socket.request.connection._peername}`);
socket.remoteAddress = socket.request.connection._peername.address;
socket.remotePort = socket.request.connection._peername.port;
console.dir(`socket.remoteAddress : ${socket.remoteAddress}`);
console.dir(`socket.remotePort : ${socket.remotePort}`);
});
11. 클라이언트 웹소켓
https://socket.io/docs/v3/client-installation/index.html
12. socket.io 클라이언트 추가(아래의 코드는 클라이언트가 서버에 붙는지 여부 확인)
** /public/client1.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>클라이언트 1</title>
<script src="https://cdn.socket.io/3.1.3/socket.io.min.js"
integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script>
let host;
let port;
let socket;
$(function() {
$('#connectButton').on('click', function(event) {
console.log('connectButton 호출!');
host = $('#hostInput').val(); // localhost
port = $('#portInput').val(); // 3000
connectToServer();
});
});
function connectToServer() {
console.log('connectToServer 호출!');
const url = `http://${host}:${port}`; // http://localhost:3000
socket = io.connect(url)
console.log('socket 객체 생성!');
socket.on('connect', function() {
console.log('웹소켓 서버에 연결했습니다.');
});
}
</script>
</head>
<body>
<!-- http://localhost:3000/public/client1.html -->
<h2>클라이언트 1</h2>
<hr/>
<p>접속 ip : <input type="text" id="hostInput" value="localhost"></p>
<p>접속 port : <input type="text" id="portInput" value="3000"></p>
<p><input type="button" id="connectButton" value="서버접속"></p>
<hr/>
<p>결과 : </p>
<div id="result"></div>
</body>
</html>
13. socket.io로 채팅 기능 구현
** /public/client2.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>클라이언트 2</title>
<script src="https://cdn.socket.io/3.1.3/socket.io.min.js"
integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script>
let host;
let port;
let socket;
$(function() {
$('#connectButton').on('click', function(event) {
console.log('connectButton 호출!');
host = $('#hostInput').val(); // localhost
port = $('#portInput').val(); // 3000
connectToServer();
});
$('#sendButton').on('click', function(event) {
const sender = $('#sender').val(); // apple
const rev = $('#rev').val(); // all
const data = $('#data').val(); // 채팅내용 ...
const output = {sender:sender, recepient:rev, commend: 'chat', type:'text', data:data}
console.log(`서버로 보낼 데이터 : ${JSON.stringify(output)}`);
if(socket == undefined) {
alert('서버에 연결하지 못했습니다. 서버 연결을 먼저 시도하세요.');
return;
}
socket.emit('message', output);
});
});
function connectToServer() {
console.log('connectToServer 호출!');
const url = `http://${host}:${port}`; // http://localhost:3000
socket = io.connect(url)
console.log('socket 객체 생성!');
socket.on('connect', function() {
console.log('웹소켓 서버에 연결했습니다.');
socket.on('message', function(message) {
console.log(JSON.stringify(message));
console.log(`수신 메시지 : ${message.sender}, ${message.recepient}, ${message.commend}, ${message.data}`);
println(`수신 메시지 : ${message.sender}, ${message.recepient}, ${message.commend}, ${message.data}`);
});
});
function println(data) {
$('#result').append(`<p>${data}</p>`);
}
}
</script>
</head>
<body>
<!-- http://localhost:3000/public/client2.html -->
<h2>클라이언트 2</h2>
<hr/>
<p>접속 ip : <input type="text" id="hostInput" value="localhost"></p>
<p>접속 port : <input type="text" id="portInput" value="3000"></p>
<p><input type="button" id="connectButton" value="서버접속"></p>
<hr/>
<p>보내는 사람 아이디 : <input type="text" id="sender" value="apple"></p>
<p>받는 사람 아이디 : <input type="text" id="rev" value="all"></p>
<p>메시지 : <input type="text" id="data"></p>
<p><input type="button" id="sendButton" value="전송"></p>
<hr/>
<p>결과 : </p>
<div id="result"></div>
</body>
</html>
** 1_socket_io.js
const express = require('express');
const bodyParser = require('body-parser');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const expressSession = require('express-session');
const passport = require('passport');
const static = require('serve-static');
const path = require('path');
const expressErrorHandler = require('express-error-handler');
const socketio = require('socket.io'); // npm i socket.io
const cors = require('cors'); // npm i cors
const app = express();
const router = express.Router();
app.use(cookieParser());
app.use(expressSession({
secret: '!@#$%^&^*&(',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60 * 60 * 1000 }
}));
app.use(logger('dev'));
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.urlencoded({extended: false}));
app.use('/public', static(path.join(__dirname, "public")));
app.use('/', router);
const errerHandler = expressErrorHandler({
static: {
'404': './public/404.html'
}
});
app.use(expressErrorHandler.httpError(404));
app.use(errerHandler);
app.set('views', __dirname + "/views");
app.set('view engine', 'ejs');
const config = require('./config/config');
const database = require('./database/database');
const configPassport = require('./config/passport');
configPassport(app, passport);
const userPassport = require('./routes/route_member');
userPassport(router, passport);
const server = app.listen(config.server_port, () => {
console.log(`${config.server_port} 포트로 웹 서버 실행중...`);
database.init(app, config);
});
const io = socketio(server);
console.log('socket.io 서버 준비 완료!');
io.sockets.on('connection', (socket) => {
console.dir(`connection : ${socket.request.connection._peername}`);
socket.remoteAddress = socket.request.connection._peername.address;
socket.remotePort = socket.request.connection._peername.port;
console.dir(`socket.remoteAddress : ${socket.remoteAddress}`);
console.dir(`socket.remotePort : ${socket.remotePort}`);
socket.on('message', function(message) {
console.log('message 이벤트를 받았습니다.');
console.dir(message);
if(message.recepient == 'all') {
console.log('모든 클라이언트에게 메시지를 보냅니다.');
io.sockets.emit('message', message);
}
});
});
'웹_프론트_백엔드 > 프론트엔드' 카테고리의 다른 글
2021.03.20 (0) | 2021.05.11 |
---|---|
2021.03.20 (0) | 2021.04.20 |
2021.03.13 (0) | 2021.04.17 |
2021.03.07 (0) | 2021.04.02 |
2021.03.06 (0) | 2021.03.14 |