해결된 질문
22.05.09 13:32 작성
·
1.4K
0
강사님 안녕하세요
질문드리기 전에, http 쿠키와 세션 강의를 먼저 복습했습니다
아래처럼 정리했습니다
서버측에서 클라이언트를 구분하기 위해 보내는 게 쿠키
쿠키의 중요한 정보를 클라이언트의 브라우저로 보내면 보안위험이 있고
그래서 쿠키의 중요한 정보는 서버에서 갖고, 클라이언트에게 안보내서,
브라우저에서는 중요정보는 못알아내도록 서버에서 관리하는 게 세션
예를 들면 4장의 session.js에서는 쿠키의 name 대신, 현재 시간을 보낸다
라고 복습하고 http 세션 코드도 복습했습니다
그리고나서 cookie2.js를 익스프레스 코드로 변환시킨 코드를
이번에는 session을 이용한 코드로 변경해보려고 했습니다
const express = require('express');
const path = require('path');
const { nextTick, rawListeners } = require('process');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const session = require('express-session');
const { connect } = require('http2');
const app = express();
app.set('port', process.env.PORT || 3000); //'port' 라는 속성에 포트번호 3000번을 설정합니다.
//서버의 포트를 3000번으로 지정합니다.
app.use(morgan('dev'));
//app.use(morgan('dev'));
//쿠키를 객체화 시킵니다.
app.use(cookieParser('zerochopassword'));
//cookieparser를 사용하기 위해
//app.use('/',express.static(__dirname, 'kkk'))
app.use(express.static(path.join(__dirname, 'kkk')))
app.use(express.json());
app.use(express.urlencoded({extended: true}));
//post요청에 의한 req.body를 사용하기 위해서
console.log(path.join(__dirname, 'kkk'))
//login 경로의 경우입니다.
app.get('/login', (req, res, next) => {
req.cookies // 쿠키 객체화
const expires = new Date();
expires.setMinutes(expires.getMinutes() + 5);
res.cookie('name', encodeURIComponent(req.query.name),{
expires: expires,
httpOnly: true,
path: '/',
})
// app.use(session({
// name: 'connect.sid',
// resave: false,
// saveUninitialized: false,
// secret: 'zerochopassword',
// cookie:{
// expires: expires,
// httpOnly: true,
// path: '/',
// },
// }));
// req.session.id = req.query.name;
res.redirect('/');
});
app.get('/', (req,res)=>{
console.log("req.url "+req.url);
if(req.cookies.name)//name이라는 쿠키가 있는 경우입니다.
{
//res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.send(`${req.cookies.name}님 안녕하세요`);//쿠키에 넣은 이름이 웹페이지에 출력됩니다
}
else{ //로그인도 아니고, 쿠키도 없는 경우입니다.
//next(createError(404));
try {
// console.log("진입");
//res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
//익스프레스에서는 writeHead를 쓰면 안된다 에러가 생긴다
//res.send( ) 할 때 이미 자동으로 res.status().send() 이런 식으로 헤더를 설정해준다
//res.sendFile(path.join(__dirname, '/cookie2.html'));//cookie2.html 파일을 클라이언트에게 보내준다
//console.log(err.status)
console.log("진입");
res.setHeader('Content-Type', 'text/html');
//익스프레스에서는 writeHead를 쓰면 에러가 생긴다 그러므로 setHeader를 써라
res.sendFile(path.join(__dirname, 'cookie2.html')); //cookie2.html 파일을 클라이언트에게 보내준다
} catch (err) {
// res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
// res.end(err.message);
next(err); //콜백함수에 err 라는 인자가 있는 app.use로 이동한다
}
}
});
// app.get('/:id',(req,res)=>{
// console.log("req.url "+req.url);
// console.log("req.params.id "+req.params.id);
// res.send(`Hello ${req.params.id}`);
// })
//아래는 에러처리입니다.
app.use((req,res,next)=>{ // 찾는 경로가 없으면 get을 다 지나서 use로 온다
console.log("req.url "+req.url);
next(createError(404)); //찾는 경로가 없으면 404처리
})
app.use((err,req,res,next)=>{ // /favicon.ico도 여기로 간다 에러도 여기로 간다
console.log("req.url "+req.url);
console.log(res.locals.message);
res.locals.message = err.message;
res.locals.error = req.app.get(`env`) === `development` ? err:{};
console.log(err.status)
res.status(err.status ||500).send(err.message);
});
app.listen(3000, () => {
console.log(app.get('port'), '번 포트에서 서버 대기 중입니다!');
});
저는 아래처럼 변경해봤습니다
공식문서도 참고했습니다
프로덕션 환경의 Express를 위한 보안 우수 사례 (expressjs.com)
그런데 로그인을 하면 세션이 안생겨서 혹시 제가 잘못 알고있는 부분을 가르쳐주시면 감사하겠습니다
+
그리고 63행과 66행에서 req.cookies.name을 req.session.id로 변경해도 에러가 해결이 안되더라구요
답변 2
1
1
2022. 05. 09. 14:50
이것도 완전 포인트를 잘못 잡고 계신데요. express-session은 res.cookie같은 걸 쓰는 게 아닙니다. 그리고 app.get 안에서 app.use를 써서도 당연히 안 되고요.
그냥 req.session에다가 값을 넣으면 알아서 브라우저로 connect.sid 쿠기가 보내집니다.
req.session.id는 수정하실 수 없고요.
req.session.name = req.query.name만 하면 됩니다.
4장에서 한 건 진짜 수동으로 직접 한 것이고, 6장에서 하는 건 익스프레스에서 편의를 제공해서 편하게 하는 겁니다. 4장에서보다 6장 코드가 길다? 그럼 문제가 있는 겁니다.
2022. 05. 09. 15:40
아뇨 connect.sid는 req.session.name도 아니고 req.session.id도 아니죠. connect.sid는 쿠키 이름입니다. 그 값으로 req.session.id를 찾을 수 있는 것이고요.
2022. 05. 09. 15:41
네 맞습니다. 익스프레스 세션이 알아서 해주는 작업들이 있어서 완벽하게 1대1은 아닙니다. 그런데 session.js는 구린 코드고 익스프레스쪽은 좋은 코드이므로 굳이 구린 코드와 1대1 대응시킬 필요가 없습니다.
3번째로 드리고 질문입니다
session이 서버에서 관리하는데 res.session 이 아닌 req.session 인 이름이 궁금한데, 이건 그저 더 이해하려고 하면 안되는 익스프레스 약속 정도로 넘어가야겠죠?
4번째로 드리고 싶은 질문도 있는데요
session을 쓰는 게 쿠키를 쓰는 것 보다 좋잖아요
그러면 현업자분들은
GET 요청은 req.query를 주로 쓰고
POST 요청은 req.session을 주로 쓰나요?
저번 수업에서 req.body를 쓰면 옛날 스타일이고, req.cookies를 쓰면 최신 스타일이라고 가르쳐주신 게 기억나서요
session 코드를 사용하면 cookie 코드는 사용 안하니까
req.cookies보다도 req.session을 더 많이 사용하시나요?
강사님 문득 궁금해진 게 있습니다
http 모듈에서는 session[고유값] 이렇게 객체 배열의 인덱스에 고유값이 들어가고
익스프레스에서는 req.session.id = 고유값 이렇게 id 속성에 고유값이 들어가더라구요
그러다가 한번 생각해보니
서버쪽에서 클라이언트의 name을 알아내고 싶으면
그 클라이언트의 고유값을 알아내서 session[고유값].name 이렇게 접근하면 될 것 같았습니다
그런데, 익스프레스에서는
req.session이 배열이 아니라서
고유값을 알아내도 접근 자체가 불가능할 것 같더라구요
왜냐하면 클라이언트가 로그인할 때 고유값이 10 인 것을 알아내도
http에서는 session[10].name 으로 클라이언트 아이디를 알아낼 수가 있었습니다
이렇게 session이 배열이면 여러사람의 세션쿠키를, 서버에서 한번에 관리한다는 게 느껴졌습니다
어떤 클라이언트는 고유값이 10이고 어떤 클라이언트는 고유값이 20이면
이 사람들의 세션정보는 session[10], session[20] 이렇게 서버에 보관이 되는데요
반면에 익스프레스에서는
한 사람의 세션쿠키만 관리하는 것 같았습니다
req.session은 배열이 아니라서 그렇게 느껴졌습니다
어떤 클라이언트는 서버에 접속할 때 req.session.id 가 200이고
어떤 클라이언트는 서버에 접속할 때 req.session.id가 300이면
req.session은 배열이 아닌데, 이 여러사람의 정보를 담는다는 게 이해가 어려웠습니다
req.session이 배열이 아닌데, 익스프레스는 어떻게 많은 클라이언트의 로그인 정보를 알 수 있는지 질문드리고 싶습니다
2022. 05. 09. 20:43
req.session은 그때그때 메모리에서 세션 객체를 불러오는 겁니다. req.session에 세션을 저장하는게 아니라 세션에서 찾아서 req.session에 담는겁니다.
2022. 05. 09. 22:20
bodyparser를 쓰면 옛날사람이라고 말씀하신 부분을, 제가 req.body와 혼동한 것 같습니다
bodyParser는 deprecated 되었다는 맥락으로 말씀하신 것 같은데
제가 req.body와 동일시해서 생각한 것 같습니다 죄송합니다