-
esspress - Middleware(미들웨어)2카테고리 없음 2023. 2. 16. 11:15
Middleware
express.json, express.urlencoded
클라이언트에서 post, put 요청 시 들어온 정보를 가진 req.body에 접근하기 위해 필요하 미들웨어이다. 이경우 요청 정보가 url에 들어온 것이 아니라 request body에 들어있는데, 이 값을 읽을 수 있는 구문으로 파싱하고, req.body로 옮겨주는 역할을 하는 것이 express.json, express.urlencoded이다.
app.use(express.json()); app.use(express.urlencoded({ extended: true }));
원래는 boby-parser라는 미들웨어를 npm install을 통해 다운받아 장착해주어야 했는데, 이제는 express에 내장되어 express.json,express.urlencoded 메서드를 통하여 사용할 수 있다.
express.json은 req.body가 json 형태일 때, express.urlencoded는 폼에 대한 요청일 때 사용한다. express.urlencoded의 extended 옵션은 false로 설정하면 node.js에 내장된 queryString을 사용하고 true로 설정하면 npm의 qs 모듈을 사용한다.
둘다 url 쿼리 스트링을 파싱해 주지만 qs는 보안이 추가적으로 필요할 때 사용한다. 그리고 req.body가 이미지, 동영상 등의 multipart 형식의 데이터라면 multer 등 다른 미들웨어를 추가적으로 설치해서 처리해주어야 한다.
cookie(쿠키)와 session(세션)
클라이언트에게서 요청을 받을 때, 사용자의 정보에 관해서는 IP주소와 브라우저의 정보 정보만 알수 있다. 따라서 그 정보만을 가지고 사용자를 식별하기 힘들기 때문에 로그인을 구현하는 것이다. 그리고 로그인을 구현할 때 쿠키와 세션이 사용된다.
HTTP 쿠키
쿠키(웹 쿠키, 브라우저 쿠키)는 서버가 사용자의 웹 브라우저에 전송하는 작은 데이터 조각이다. 브라우저는 그 데이터 조각을 저장했다가, 동일한 서버에 재 요청 시 작은 데이터 조각인 쿠키를 함께 전송한다. 따라서 쿠키는 두 요청이 동일한 브라우저에서 왔는지 아닌 판단할 때 주로 사용된다.
이를 이용하면 사용자의 로그인 상태를 유지할 수 있는데 상태가 없는(stateless)HTTP 프로토콜에서 상태 정보를 기억해주기 때문이다.
쿠키의 세가지 목적
- 세션 관리(Session management) : 서버에 저장해야 할 로그인,장바구니, 게임 스코어 등의 정보 관리
- 개인화(Personalization) : 사용자 선호, 테마 등의 세팅
- 트래킹(Tracking) : 사용자 행동을 기록하고 분석하는 용도
추가로 찾아 볼것
modern storage APIs
https://developer.mozilla.org/ko/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
쿠키 만들기
HTTP 요청을 수신할 때, 서버 응답과 함께 Set-Cookie 헤더를 전송할 수 있다. 쿠키는 보통 브라우저에 저장되며, 그 후 해당 쿠키가 만들어진 서버에 요청(Request)을 보낼때 쿠키가 HTTP 헤더안에 포함되어 전송된다. 쿠키는 추가 설정을 이용하여 만료일 혹은 지속시간(duration)도 명시할 수 다. 만료된 쿠키는 더이상 사용되지 않느다. 추가적으로, 특정 도메인 혹은 경로 제한을 설정할 수 있으며 또한 쿠키가 보내지는 것을 제한 할 수도 있다.
{ Set-Cookie: <cookie-name>=<cooie-value> }
cookie-parser
요청된 쿠키를 쉽게 추출할 수 있도록 도와주는 미들웨어이다. express의 request(req)객체에 cookies 속성을 부여할 수 있다.
클라이언트가 요청을 보낼 때마다 키-쌍(name=surge100)으로 이루어진 쿠키를 보내고 서버에서는 클라이언트가 보낸 쿠키를 읽어 사용자가 누군지를 식별하게 되는 것이다. 이때 보안이 필요한 출입구에 들어갈때 출입증이 있어야만 게이트를 통과할 수 있는 것 처럼 쿠키는 그 출입증 같은 역할을 하는 존재이다.
cookie.js
const http = require("http"); http .createServer(() => { res.writeHead(200, { "Set-cookie": "name=surge100" }); console.log(req.headers.cookie); res.end("Cookie --> Header"); }) .listen(8060, () => { console.log("8060포트에서 서버 연결 중"); });
처음에 한 번만 서버에서 res.writeHead()메서드를 통해 'Set-cookie'에 값을 넣어 준다. 그러면 브라우저에 키-쌍으로 이루어진 쿠키가 헤더에 저장이된다. 이렇게 한번 설정되고 난 후에는 브라우저에서 자동으로 쿠키를 매번 요청할 때마다 서버에게 보낸다.
브라우저를 끄지 전까지만 쿠키가 살아있게 되는데, 그 이유는 쿠키 expire를 지엉해주지 않았기 때문에 기본 값으로 브라우저를 끄게 되면 쿠키 값이 없어진다. 이렇게 쿠키 값을 통해 쿠키가 있을 때는 사용자 관련 화면을, 없을 때는 로그인 화면을 보내주는 식으로 로그인을 구현할 수 있다.
const express = require("express"); const cookieParser = require("cookie-parser"); const app = express(); app.set("port", process.env.PORT || 8070); app.use(cookieParser()); app.get("/cookie", function (req, res) { console.log("Cookies:", req.cookies); console.log("typeof req.cookies:", typeof req.cookies); }); app.listen(app.get("port"), () => { console.log(app.get("port"), "번 포트에서 서버 실행중"); });
클라이언트가 쿠키와 함께 요청을 보내면 req.headers.cookie를 통해 쿠키 값에 접근을 할 수 있게 된다. req.headers.cookie에 저장된 값은 문자열인데, 이를 자바스크립트에서 사용하기 위해서는 객체로 *파싱하는 과정이 필요하다. Cookie-parser없이 파싱하려면 따로 조금 복잡한 함수를 만들어주어야 한다.
*파싱(Parsing):데이터를 원하는 형태로 가공하는 과정이다.
Cookie-parser를 사용하면 따로 파싱하는 함수를 만들어줄 필요 없이 express의 req 객체에 cookies 속성이 부여되므로 res.cookies(쿠키명)을 통해 쿠키 값에 접근을 할 수 있게 된다.
express-session
쿠키만 사용하게 되면 개발자도구 [Application] 탭의 Cookies에서 쿠키 값을 확인할 수도 있고 값을 바꿀 수도 있게 된다. 따라서 실제 정보는 서버에만 저장해두고 브라우저에는 암호화된 키 값만 보낸뒤 그 키 값으로 실제 값에 접근할 수 있도록 하는 것을 Session(세션)이라고 한다.
const http = require("http"); const session = {}; const sessKey = new Date(); session[sessKey] = { name: "surge100" }; http .createServer((req, res) => { res.writeHead(200, { "Set-cookie": `session=${sessKey}` }); res.end("Session-Cookie --> Header"); }) .listen(8060, () => { console.log("8060포트 서버 연결 중..."); });
session 저장용 객체 하나를 session이라는 변수에 생성하고, session의 속성의 key값을 sessKey라는 변수에 생성해서 담는다. 위 코드에서는 현재 날짜를 구해서 담았는데, express-session 미들웨어를 이용하면 임의의 키 값을 생성할 수 있게 된다.
session 객체에 속성 중 하나의 key값으로 sessKey에 담긴 값을 지정해주고 해당 key에 상을 하는 value로 {name:'surge100'}을 할당한다. 그리고 앞서와 값이 쿠키 값을 바로 보내주는 것이 아니라 세션객체의 속성의 key값으로 지정된 값을 넣어준다.
그렇게 되면 쿠키 값이 바로 뜨는 것이 아니라 session값이 보여지게 된다. 이 session도 마찬가지로 express-session cookies.session 값을 이용해서 session을 다루어야 하지만 express-session을 이용한다면 req객체에 session속성이 부여되여 req.session을 통해 접근할 수 있게 된다.
미들웨어 통합 테스트
const express = require("express"); const morgan = require("morgan"); const cookieParser = require("cookie-parser"); const session = require("express-session"); const app = express(); /* 포트설정 */ app.set("port", process.env.PORT || 8070); /* 미들웨어 */ app.use(express.static(__dirname + "/public")); app.use(morgan("dev")); app.use(cookieParser("secret@1234")); //암호화된 쿠키를 사용하기 위한 임의의 문자 전송 app.use( session({ secret: "secret@1234", // 암호화 resave: false, //새로운 요청 시 세션에 변동 사항이 없어도 다시 저장할지 설정 saveUninitialized: true, //세션에 저장할 내용이 없어도 저장할지 설정 cookie: { //세션 쿠키 옵션 설정들 httpOnly, expires, domain, path, secure, sameSite httpOnly: true, //로그인 구현 시 필수 적용, 자바스크립트로 접근 할 수 없게 하는 기능 }, // name : 'connect.sid' //세션 쿠키의 Name 지정 default가 connect.sid }) ); app.use(express.json()); app.use(express.urlencoded({ extended: true })); /* 라우팅 설정 */ app.get("/", (req, res) => { if (req.session.name) { const output = `<h2>로그인한 사용자님</h2><br> <p>${req.session.name}님 안녕하세요.</p><br> `; res.send(output); } else { const output = `<h2>로그인하지 않은 사용자입니다</h2><br> <p>로그인 해주세요.</p><br> `; res.send(output); } }); app.get("/login", (req, res) => { //실제 구현시 post console.log(req.session); //쿠키를 사용할 경우 쿠키에 값 설정 //res.cookie(name,value,options) //세션 쿠키를 사용할 경우 req.session.name = "surge100"; res.end("Logout Ok"); }); /* 서버와 포트 연결 */ app.listen(app.get("port"), () => { console.log(app.get("port"), "번 포트에서 서버 실행중"); });
위 코드를 실행해 보면 위와 같은 콘솔 log를 확인할 수 있다. 이는 app.use()에 morgan을 장착했기 때문에 요청 메서드, url, 상태코드, 응답 속도 등의 정보가 로그로 표시된 것이다.
/login 페이지로 접속 시 쿠키 세션을 사용해 req.session.name이라는 속성을 설정해 값으로 'surge100'이라는 문자열을 넣어주었고 브라우저를 닫을 때까디 req.session.name 값은 유효하다.
안전하게 cookie를 전송하기 위해서 cookie를 서명해야 하기 때문에 secret 값이 필요하다. 그래서 app.use(cookieParser())의 인자 값과 app.user(session({}))의 객체 인자의 secret 속성을 같은 값을 동일하게 설정한다.
express-session을 사용하면 req의 속성중 하나로 session을 가지게된다. 따라서 req.session은 방금 서버로 요청을 보낸 사람의 고유한 저장 공간 같이 사용할 수 있게 된다. 즉 req.session.name = 'surge100'이란 key-value 속성을 설정하면 해당 요청을 보낸 사람의 로컬(브라우저)에만 req.session.name만 'surge100'이라는 값을 가지게 되는 것이다.
즉 이제는 응답을 통해 cookie에 req.session.name에 'surge100'이라는 값을 설정 받은 로컬(브라우저가) 동일한 서버에 요청을하면 req.session.name에 'surge100'이라는 문자열을 가지고 요청(request)을 보내게 된다. 그래서 localhost:8070에 접속했을 때 위와 같은 화면이 반환 된다.
미들웨어 morgan,cookie-parser 등 에는 모두 next()가 내장되어있기 때문에 자동으로 다음 미들웨어로 넘어가게 된다. 단 static의 경우 next( )가 없기 때문에 static을 거쳐야 하는 router라면 공통 미들웨어 순서를 잘 설정해 준어야 한다.