일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 동영상
- mvvm
- junit
- GCP
- paging
- Android
- databinding
- google play
- node
- SwiftUI Tutorial
- node.js
- mysql
- rx
- Android 13
- PagingLib
- Reactive
- MotionLayout
- SWIFTUI
- MediaSession
- liveData
- Kotlin
- Animation
- RxKotlin
- Koin
- list
- 인앱결제
- 테스트 자동화
- MediaPlayer
- android13
- Observable
- Today
- Total
봄날은 갔다. 이제 그 정신으로 공부하자
node.js로 웹서비스 만들기 (5. 세션 관리) 본문
개발 환경을 구성하고 DB연결하고 라우터 처리까지했으니 이제 세션 관리 기능을 개발해야 합니다.
힘드네요...
세션이란?
세션은 서버에 저장되는 key-value 형식의 데이터로 세션은 서버에서만 생성 할 수 있어 사용자의 로그인 상태를 확인할 때 사용 됩니다.
세션의 동작
서버측에서 세션을 생성할 땐, 클라언트에게 SID(session ID)를 발급합니다.
SID가 발급되면 connect.sid 쿠키가 생성된 것을 확인 할 수 있습니다.
서버측엔 해당 클라이언트가 사용할 세션을 저장합니다. 클라이언트에 SID 쿠키가 저장되어 있으니 클라이언트로부터 request가 오면 request의 쿠키로부터 SID를 확인 할 수 있으므로 해당 클라이언트의 세션을 매핑해 사용할 수 있습니다.
세션 사용 방법
Express-session 설치
node.js에서 세션을 사용하기 위해서는 우선 아래와 같이 express-session을 설치합니다.
> npm install express-session
미들웨어 추가
세션을 사용하기 위해서는 아래와 같이 미들웨어를 등록해야 합니다.
// index.js
const expressSession = require('express-session');
app.use(
expressSession(
{
secret: "myKey", // [필수] SID를 생성할 때 사용되는 비밀키로 String or Array 사용 가능.
resave: true, // true(default): 변경 사항이 없어도 세션을 다시 저장, false: 변경시에만 다시 저장
saveUninitialized: true // true: 어떠한 데이터도 추가되거나 변경되지 않은 세션 설정 허용, false: 비허용
})
);
미들웨어 옵션
- cookie: ID 쿠키에 대한 설정으로 cookie 옵션은 객체 형식으로 줄 수 있으며 default는 { path: '/', httpOnly: true, secure: false, maxAge: null }입니다.
- path: String, 쿠키를 전송할 경로를 지정합니다. 세션의 경우 session을 사용하게 될 path를 정해주는 역할을 합니다. 정해진 path가 아닌 경로에 접근하면 session이 없는 것처럼 작동합니다.
- httpOnly: Boolean, 클라이언트 측에서 쿠키에 접근하는 것을 막습니다. 즉, document.cookie를 통한 쿠키 접근을 막습니다.
- secure: Boolean, https 통신에서만 쿠키 전송을 허용합니다. express-session 개발자는 secure: true를 사용할 것을 권장.
- maxAge: 쿠키가 유지될 기간으로 초 단위로 설정할 수 있습니다. 세션을 통한 로그인 유지를 구현하려면 maxAge를 설정해야 함.
- genid: SID로 사용할 로직을 정의하는 옵션으로 genid: function(req){}형식으로 사용하면 되고, SID로 사용할 String을 return 하면 됩니다. default로 uid-safe 라이브러리를 통한 SID 생성 함수를 사용합니다.
- name: SID 쿠키의 이름을 설정합니다. default는 connect.sid입니다.
- proxy: 리버스 프록시를 사용하는 경우 설정하는 옵션입니다. true로 설정하면 X-Forwarded-Proto 헤더가 사용됩니다. default는 undefined로, express에 trust proxy로 등록된 주소에 대해서만 세션이 동작합니다.
- resave: express-session은 기본적으로 세션에 변경이 있을 때만 세션을 저장합니다. resave:true로 설정한다면 변경사항이 없어도 session을 다시 저장합니다. default는 true입니다. false로 설정하면 불필요한 session 저장을 막아주기 때문에 보통 false로 설정합니다.
- saveUninitialized: 세션이 생성되었지만 어떠한 데이터도 추가되거나 변경되지 않은 상태를 uninitialized 라고 합니다. saveUninitialized:true로 설정한다면 uninitialized session도 저장합니다. false로 설정하면 uninitialized session은 저장하지 않으므로 리소스 활용 측면에서 조금 더 유리합니다.
- rolling: 세션이 만료되기 전, 새로 고침 또는 페이지 이동이 일어나면 세션 만료를 갱신하는 옵션입니다. default는 rolling:false
세션 메소드
session에서 사용 가능한 메소드는 다음과 같습니다.
- regenerate(callback): 세션을 재생성하는 메소드로 새로운 SID를 부여합니다. 사용 방법은 아래와 같습니다.
req.session.regenerate(function(err){
// will have a new session here
})
- destroy(callback): 세션을 명시적으로 삭제하는 메소드로 사용 방법은 아래와 같습니다.
req.session.destroy(function(err){
// cannot access session here
})
- reload(callback): store에 저장된 session date를 다시 불러오는 메소드로 사용 방법은 아래와 같습니다.
req.session.reload(function(err){
// session updated
})
- save(callback): 세션을 store에 명시적으로 저장하는 메소드로 response의 마지막에 session을 자동으로 저장하기 때문에 보통은 사용하지 않아도 됩니다. 사용 방법은 아래와 같습니다.
req.session.save(function(err){
// session saved
})
- touch(callback): 명시적으로 세션의 maxAge를 갱신하는 메소드로 rolling 옵션의 역할과 비슷한 기능을 수행하는 메소드로 사용 방법은 아래와 같습니다.
req.session.touch()
세션에 포함된 변수들
- session.id, sessionID: sessionID는 변경 불가능한 값으로 session을 load하거나 생성할 때 부과되는 값 입니다. 세션이 갱신되면 이 값도 변경이 됩니다. req.session.id는 req.sessionID의 별칭(alias)입니다.
- session.cookie: SID 쿠키의 설정값이 들어 있습니다. 이 값은 SID와 달리 수정할 수 있어서 사용자마다 다르게 쿠키를 설정해 줄 수 있습니다.
세션 예제
아래 코드는 간단한 세션 사용 예제 입니다.
우선 아래와 같이 필요한 것들을 설치합니다.
// package.json
{
"name": "nodesession2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "nodemon index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.20.2",
"bootstrap": "^5.3.0",
"cookie-parser": "^1.4.6",
"ejs": "^3.1.9",
"express": "^4.18.2",
"express-session": "^1.17.3",
"nodemon": "^2.0.22",
"serve-static": "^1.15.0"
}
}
index.js 파일에 로그인 & 로그아웃 등 세션 관리 기능을 추가해줍니다.
세션 관리를 하는 index.js에 아래와 같이 root 라우터로 등록해 다른 라우터에서도 세션 기능을 사용할 수 있도록 합니다.
var router = express.Router();
...
app.use('/', router);
전체 소스는 아래와 같습니다.
// index.js
const express = require('express');
const serveStatic = require('serve-static');
const cookieParser = require('cookie-parser');
const expressSession = require('express-session');
const bodyParser = require('body-parser');
const path = require('path');
const app = express();
app.set("port", 3000);
// view engine 템플릿 사용을 명시
app.set('views' , path.join(__dirname, 'views'));
app.set('view engine' , 'ejs');
// 라우터 생성
var mainRouter = require('./routes/main');
var router = express.Router();
// 미들웨어를 등록한다.
app.use(serveStatic(path.join(__dirname, "public")));
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: false
})
);
// cookie and session assign middleWare
app.use(cookieParser());
// 세션 세팅
app.use(
expressSession(
{
secret: "myKey",
resave: true,
saveUninitialized: true,
})
);
app.use('/', router);
app.use('/main', mainRouter);
router.get('/', function(req, res){
console.log('[GET] root');
if(req.session.user){
res.redirect('/main/intro');
} else {
res.render('login');
}
});
router.get('/login', function(req, res){
console.log('[GET] auth login');
res.render('login');
});
router.post('/login', function(req, res){
console.log('[POST] auth login');
const paramID = req.body.id || req.query.id;
const pwd = req.body.password || req.query.password;
console.log(' id: ' + paramID + ', password: ' + pwd);
if(req.session.user){
console.log(' 이미 로그인 되어 있습니다.');
} else {
console.log(' 사용자 정보 저장');
// 세션에 유저가 없다면,
req.session.user = {
id: paramID,
pwd: pwd,
name: "MyName!!!",
authorized: true,
};
res.redirect('/main');
// res.render('intro');
}
});
//router.route('/logout').get(function(req, res){
router.get('/logout', function(req, res){
if(req.session){
req.session.destroy(()=>{
res.redirect('/');
});
}
});
app.listen(app.get("port"), () => {
console.log(`${app.get("port")}에서 서버실행중.`);
});
// routes/main.js
const express = require('express');
const bodyParser = require('body-parser');
var router = express.Router();
// 미들웨어를 등록한다.
router.use(bodyParser.json());
router.get('/', function(req, res){
console.log('[GET] main root');
if(!req.session.user){
console.log(' 어라? 로그인이 안되어 있네? 로그인 화면으로...');
res.render('login');
return;
}
res.render('intro');
});
router.get('/intro', function(req, res){
console.log('[GET] main intro');
if(!req.session.user){
console.log(' 어라? 로그인이 안되어 있네? 로그인 화면으로...');
res.render('login');
return;
}
res.render('intro');
});
module.exports = router;
로그인 & 메인 화면은 아래와 같이 구현합니다.
// views/login.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<title>로그인</title>
</head>
<body>
<h2>로그인</h2>
<form method="post" action="/login">
<div>
<label>ID: </label>
<input type="text" name="id"/>
</div>
<div>
<label>PASSWORD: </label>
<input type="text" name="password"/>
</div>
<div>
<input type="submit" value="로그인"/>
</div>
</form>
</body>
</html>
// views/intro.ejs
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<title>Example</title>
</head>
<body>
<p>로그인 되었습니다.</p>
<a href="/logout">로그아웃</a>
</body>
</html>
주의 사항 (이라고 쓰고 내가 삽질한 기록이라고 읽음.)
간단한 샘플프로그램에서 세션 기능을 구현했을 때에는 잘 동작했는데 실제 내가 만드는 웹서비스에 세션 기능을 적용했을 때는 제대로 동작하지 않는 문제가 발생함.
원인을 파악하기 위해 여기저기 디버깅해보니 route 처리를 하면 root를 라우터로 등록해 다른 라우터에서도 세션 기능을 사용할 수 있도록 index.js에 아래 코드를 추가해주어야 하는데 이걸 빼먹은 것 이었음...
-> app.use('/', router);
저거 한줄 때문에 엄청 고생함.
'학습' 카테고리의 다른 글
node.js로 웹서비스 만들기 (7. 로컬 경로에 있는 이미지 보여주기) (0) | 2023.07.09 |
---|---|
node.js로 웹서비스 만들기 (6. 팝업 띄우기) (0) | 2023.07.07 |
node.js로 웹서비스 만들기 (4. Router 분산을 통한 복잡도 관리) (0) | 2023.07.03 |
node.js로 웹서비스 만들기 (3. 기본적인 mysql query) (0) | 2023.07.01 |
node.js로 웹서비스 만들기 (2. mysql 설정하기) (0) | 2023.06.29 |