📝
016_session\session// 파일이름 : 016_session\app1_1.js
// npm init --yes
// npm i express
// npm i nodemon --save-dev
const express = require('express');
const app = express();
app.use(express.json());
app.get('/', (req, res, next) => {
// console.log(req);
// console.log(res);
console.log(req.headers.cookie) // 만료시간이 없어서(만료시간 없는 쿠키를 세션 쿠키, 브라우저 닫으면 삭제됩니다.)
// 개발자 도구 네트워크 탭과 애플리케이션에서 확인 가능합니다.
// 애플리케이션 탭에서 삭제도 가능합니다.
// test url : http://localhost:8080/
res.writeHead(200, {'Set-Cookie' : 'id=hojun' }); // 이름바꿔가면서 test
// 만료시간 = new Date();
// 만료시간.setMinutes(만료시간.getMinutes() + 1); // 1분 후 만료
// id=hojun; age=10; hello=world; Expires=만료시간; HttpOnly;
res.end('cookie!!');
});
app.use((req, res, next) => {
res.status(404).send('못찾음!'); // res.send는 res.status(200).send('')
// 보안상 status는 좀 더 고민해본 후 작성, 200을 일부러 보내주는 경우가 많습니다.
});
app.use((err, req, res, next) => {
console.log('애러발생!');
console.log(err);
});
// 매개변수가 4개인것만 애러처리합니다. 주의해주세요.
app.listen(8080); // 보통 위에 있고 맨 마지막에는 error 처리하는 경우가 많음
// 파일이름 : 016_session\app1_2.js
// npm init --yes
// npm i express cookie-parser // 굳이 할 필요가 없지만 쿠키관련된 강의니 넣어놓습니다.
// npm i nodemon --save-dev
const express = require('express');
const cookieParser = require('cookie-parser'); // 개발자도구 Network > Headers에 보안관련된 값들을 넣어줌
const app = express();
app.use(express.json());
app.use(cookieParser());
// post로 전달한 것은 body에서 꺼내 읽을 수 있죠.
// 만약 실제 로그인이었다면
// 1. post로 전달된 ID, PW가 맞는지 확인 후
// 2. 맞으면 session 성성 후 쿠키값을 user에게 전달, 여기서 쿠키값에 민감한 데이터를 넣지 않습니다.
// 3. 사용자가 쓴 블로그 등의 값이 쿠키값하고 같이 전달되면
// 4. session에서 비교후 저장
// post로 전달된 값을 set-cookie 안에 넣고
// 이제 로그인 한 값을 저장만 하면 되는 것입니다.
app.get('/', (req, res, next) => {
console.log(req.headers.cookie);
res.writeHead(200, {'Set-Cookie' : 'session=abcde' }); // 이름바꿔가면서 test
if (req.cookies.session){
if (req.cookies.session == 'abcde'){
//abcde라는 것은 아래처럼 매핑이 되어 있는 상태인거죠.
session = {'abcde':'hojun'} //서버에 저장되어 있는 session이라 생각해주세요.
return res.end(${session['abcde']}, welcome our homepage!!);
} else {
// 만료시간을 지정하지 않았기 때문에 이 구간으로 들어오진 않습니다.
// id=hojun; age=10; hello=world; Expires=만료시간; HttpOnly;
// 위와 같이 지정해줄 수 있지만 이렇게 사용할 것이 아니기 때문에 지정하지 않은 것입니다.
return res.end('로그인 지속 시간이 지났습니다. 재 로그인 해주세요.')
}
} else {
return res.end('hello!');
}
});
app.use((req, res, next) => {
res.status(404).send('못찾음!'); // res.send는 res.status(200).send('')
// 보안상 status는 좀 더 고민해본 후 작성, 200을 일부러 보내주는 경우가 많습니다.
});
app.use((err, req, res, next) => {
console.log('애러발생!');
console.log(err);
});
// 매개변수가 4개인것만 애러처리합니다. 주의해주세요.
app.listen(8080); // 보통 위에 있고 맨 마지막에는 error 처리하는 경우가 많음
// 파일이름 : 016_session\app1_3.js
// npm init --yes
// npm i nodemon --save-dev
// npm i express express-session
const express = require('express');
const session = require('express-session'); // 이렇게 생성하면! req.session이 생성이 됩니다!
const app = express();
app.use(express.json());
// 브라우저는 key값 정도만, 중요한 정보는 서버에만 저장.
// 9장에서 했던 내용입니다.
app.use(session({
secret: 'hello',
resave: false, // 다시 요청이 오면 세션에 변동이 없어도 저장, 저장하지 않음.
saveUninitialized: false,// 세션에 내용 없어도 저장?, 놉!
cookie: {
httpOnly: true, // javascript로 조작하지 못하도록! 정보보안! 필수!
secure: false,
},
}));
app.get('/', (req, res, next) => {
console.log(req.session);
// id 저장없이 로그인 사용자인지 판달할 수 있음. 이 test라는 값은 쿠키에서 가지고 있지 않음.
// 아래처럼 복잡하게 했던 것들이 아래 req.session으로 해결됩니다. 이미 고유한 session이에요.
if(!req.session.name){
// 이 부분에서 DB에서 데이터를 가지고 와서 ID, PW가 맞는지 확인해야겠죠?
req.session.name = 'hojun';
} else {
req.session.name = 'hojun 재접속 -> 로그인 유지';
}
res.send(접속하는 개개인이 다릅니다 : ${req.session.name});
// res.writeHead(200, {'Set-Cookie' : 'session=abcde' }); // 이름바꿔가면서 test
// if (req.cookies.session){
// if (req.cookies.session == 'abcde'){
// //abcde라는 것은 아래처럼 매핑이 되어 있는 상태인거죠.
// session = {'abcde':'hojun'} //서버에 저장되어 있는 session이라 생각해주세요.
// return res.end(${session['abcde']}, welcome our homepage!!);
// } else {
// // 만료시간을 지정하지 않았기 때문에 이 구간으로 들어오진 않습니다.
// // id=hojun; age=10; hello=world; Expires=만료시간; HttpOnly;
// // 위와 같이 지정해줄 수 있지만 이렇게 사용할 것이 아니기 때문에 지정하지 않은 것입니다.
// return res.end('로그인 지속 시간이 지났습니다. 재 로그인 해주세요.')
// }
// } else {
// return res.end('hello!');
// }
});
app.use((req, res, next) => {
res.status(404).send('못찾음!'); // res.send는 res.status(200).send('')
// 보안상 status는 좀 더 고민해본 후 작성, 200을 일부러 보내주는 경우가 많습니다.
});
app.use((err, req, res, next) => {
console.log('애러발생!');
console.log(err);
});
// 매개변수가 4개인것만 애러처리합니다. 주의해주세요.
app.listen(8080); // 보통 위에 있고 맨 마지막에는 error 처리하는 경우가 많음
// 파일이름 : 016_session\app1_4.js
// npm init --yes
// npm i nodemon --save-dev
// npm i express express-session
// 당연히 실제 이렇게 저장되진 않았겠죠?ㅎㅎ 이해하기 편하시도록 작성한 예제입니다.
const database = [
{
id:'hojun1',
pw:'12341'
}, {
id:'hojun2',
pw:'12342'
}, {
id:'hojun3',
pw:'12343'
}, {
id:'hojun4',
pw:'12344'
}
]
const express = require('express');
const session = require('express-session'); // 이렇게 생성하면! req.session이 생성이 됩니다!
const app = express();
app.use(express.json());
// 브라우저는 key값 정도만, 중요한 정보는 서버에만 저장.
// 9장에서 했던 내용입니다.
app.use(session({
secret: 'hello',
resave: false, // 다시 요청이 오면 세션에 변동이 없어도 저장, 저장하지 않음.
saveUninitialized: false,// 세션에 내용 없어도 저장?, 놉!
cookie: {
httpOnly: true, // javascript로 조작하지 못하도록! 정보보안! 필수!
secure: false,
},
}));
app.get('/', (req, res, next) => {
// 물론 passworkd는 get 요청이 아니었겠지만 이해를 돕기 위해 아래와 같이 진행합니다.
// http://localhost:8080/?id=hojun&pw=1234
console.log(req.session);
console.log(req.params);// '/'로 이어지는 부분을 뜻합니다. 여기에는 없어요.
console.log(req.query);
// id 저장없이 로그인 사용자인지 판달할 수 있음. 이 test라는 값은 쿠키에서 가지고 있지 않음.
// 아래처럼 복잡하게 했던 것들이 아래 req.session으로 해결됩니다. 이미 고유한 session이에요.
// 이 부분에서 DB에서 데이터를 가지고 와서 ID, PW가 맞는지 확인해야겠죠?
// user = database.filter(d => d.id == 'hojun1' && d.pw == '12341');
const user = database.filter(d => d.id == req.query.id && d.pw == req.query.pw);
console.log(user);
console.log(!!user[0]);
if(!!user[0]){
return res.send(${user[0].id}님 환영합니다.);
}
// 둘 중 틀린 것만 알려주면 안됩니다.
return res.send('id와 pw를 확인해주세요.');
// 이 아래 로직은 이제 앞으로 이렇게 진행됩니다,
// if(!!user[0]){
// 로그인 해야만 할 수 있는 것들
// } else {
// next()
// }
});
app.use((req, res, next) => {
res.status(404).send('못찾음!'); // res.send는 res.status(200).send('')
// 보안상 status는 좀 더 고민해본 후 작성, 200을 일부러 보내주는 경우가 많습니다.
});
app.use((err, req, res, next) => {
console.log('애러발생!');
console.log(err);
});
// 매개변수가 4개인것만 애러처리합니다. 주의해주세요.
app.listen(8080); // 보통 위에 있고 맨 마지막에는 error 처리하는 경우가 많음
// 파일이름 : 016_session\app2_1.js
// npm i jsonwebtoken
const jwt = require('jsonwebtoken');
const token = jwt.sign({
id: 'hojun',
grade: 'super gold'
}, 'token'); // 보통 이 토큰은 다른 파일에 저장합니다.
console.log(token); // token은 비밀값이 아니에요. https://jwt.io/에서 해독 가능합니다. 따라서 민감한 정보를 넣지 않도록 합니다.
// 파일이름 : 016_session\app2_2.js
// npm i jsonwebtoken
const jwt = require('jsonwebtoken');
const token = jwt.sign(
{
id: 'hojun',
grade: 'super gold'
},
'token',
{
expiresIn: 3
}); // 보통 이 토큰은 다른 파일에 저장합니다.
setTimeout(function(){
jwt.verify(token, 'token', (err, decoded) => {
console.log(err, decoded)
});
}, 4000); // 2초, 4초 해보세요.
console.log(token); // token은 비밀값이 아니에요. https://jwt.io/에서 해독 가능합니다.
// 파일이름 : 016_session\app2_3.js
// npm i jsonwebtoken
// 보통은 시크릿 키를 다른 파일에 저장한다고 했었죠?
// 다른 파일에 있는 값을 가져와 옵션 값으로 넣어주도록 하겠습니다.
const jwt = require('jsonwebtoken');
const secretKey = require('./secret').secretKey;
const options = require('./secret').options;
const token = jwt.sign(
{
id: 'hojun',
grade: 'super gold'
},
secretKey, options);
jwt.verify(token, secretKey, (err, decoded) => {
console.log(err, decoded)
});
console.log(token); // token은 비밀값이 아니에요. https://jwt.io/에서 해독 가능합니다.
// 파일이름 : 016_session\app2_4.js
// npm init --yes
// npm i jsonwebtoken bcrypt express express-session cookie-parser
// npm i nodemon --save-dev
// 모듈화까진 이 챕터에서 진행하지 않으나 좋은 글이 있어 포스팅합니다.
// https://velog.io/@josworks27/%EC%9D%B8%EC%A6%9D-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4-%EA%B5%AC%ED%98%84
// HTTP Request시 Cookie / Authorization 중 어디에 담아야 하는지에 대한 글입니다.
// https://velog.io/@neity16/NodeJS-Token-%EC%A0%80%EC%9E%A5-%EC%9C%84%EC%B9%98%EC%9D%98-%EA%B3%A0%EC%B0%B0
// 방법1로 하였을 때 postman에서 잘 들어가지만, 일반 브라우저에서는 잘 안돌아갑니다.
// 이유는 front-end에서 처리를 안해줘서 그런데요. 다음 장에서 좀 더 상세히 살펴보겠습니다.
const express = require('express');
const session = require('express-session'); // 이렇게 생성하면! req.session이 생성이 됩니다!
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt') // 외장 모듈
var cookieParser = require('cookie-parser');
// 앞서 말씀드린 것처럼 당연히 실제 이렇게 저장되진 않았습니다.
// 이해하기 편하시도록 작성한 예제입니다.
// hash = bcrypt.hashSync('p12341', 10);
const database = [
{
id : 'hojun1',
pw : '$2b$10$hiIjPbyoOESZPwr6g4mvGOekINoFSiEoHWyBCAm0v9xljfQNmRYsy', // p12341
blog : 'www.abc.co.kr'
}, {
id:'hojun2',
pw:'$2b$10$pULJYrBddj5J4hIwYzhpcuzNO41PUqFQoITtlkZqFgg7RqPa6M.xO', // p12342
blog : 'www.abc.co.kr'
}
]
//JWT 토큰 생성시 필요 비밀키, 앞 챕터에서는 파일에서 불러왔었음.
const jwtsecret = 'hello world';
const app = express();
app.use(express.json());
app.use(cookieParser());
//회원가입
app.post('/join', async (req, res, next) => {
const {id, password, blog} = req.body;
const user = database.find(u => u.id == id);
// if 동일한 아이디가 없을 때, else 있을 때
if(!user) {
const hashed = await bcrypt.hash(password, 10);
//클라이언트 측으로 부터 받은 회원 정보 저장
const newUser = {
id,
pw : hashed,
blog
};
database.push(newUser);
//JWT 토큰 생성(id와 blog 주소를 담아서)
const newUserToken = jwt.sign({id, blog}, jwtsecret,{
expiresIn : 60 * 5 // 60초 유효 토큰 test할 때에는 뒤에 값을 늘려주세요.
});
return res.status(200).json({
msg : '회원이 되신 것을 축하드립니다!',
token : newUserToken
});
} else {
return res.status(400).json({msg : '동일한 아이디가 있습니다. -> 입력한 정보와 함께 전달'});
}
});
app.get('/', (req, res, next) => {
// test1 : http://localhost:8080/?id=hojun&pw=1234
// test2 : http://localhost:8080/?id=hojun1&pw=p12341
// post로 날라온다면 const {id, pw} = req.body; 식으로 받습니다.
console.log(req.query);
const user = database.filter(d => d.id == req.query.id && bcrypt.compareSync(req.query.pw, d.pw));
console.log(user);
console.log(!!user[0]);
if(!!user[0]){
const userToken = jwt.sign({
id : user[0].id,
blog : user[0].blog
}, jwtsecret, {
expiresIn : 60 * 2, // 60초 유효 토큰 test할 때에는 뒤에 값을 늘려주세요.
issuer: 'service provider'
});
console.log(userToken); // 방식 1, 방식 2
// res.header('Authorization', 'Bearer '+ userToken); // 방식 1
return res.end(welcome ${user[0].id}!!);
// return res.cookie("x_auth", userToken).status(200).send(welcome ${user[0].id}!!); // 방식2
}
return res.send('id와 pw를 확인해주세요.');
});
//인증
app.use('/check', (req, res, next) => {
//헤더값에 포함된 토큰값 분석, 방법1
console.log('check check!!')
console.log(req.headers);
/*
// jwt.io에서 복호화 한 값
// 해커가 이 값을 조작해서 준다면?
{
"id": "hojun1",
"blog": "www.abc.co.kr",
"iat": 1635469822,
"exp": 1635469942,
"iss": "service provider"
}
// 같은 이름으로 해도 애러나고, 다른 이름으로 해도 애러 납니다.
*/
if(req.headers.authorization) {
console.log(req.headers.authorization);
console.log(req.get('Authorization'));
const token = req.headers.authorization.split(' ')[1];
jwt.verify(token, jwtsecret, (err, encode)=>{
if(err) {
console.error(err)
return res.send('세션 만료되었습니다!');
} else {
console.log(encode);
return res.send(hello world!! ${encode.id});
}
});
}
return res.send('로그인 안하셨는데요?!');
//
// const userToken = auth.split(' ')[1];
// 방법2
//클라이언트 쿠키에서 토큰을 가져온다.
// let token = req.cookies.x_auth;
// 토큰을 복호화 이후는 방법 1과 동일합니다.
});
app.use((req, res, next) => {
res.status(404).send('못찾음!');
});
app.use((err, req, res, next) => {
console.log('애러발생!');
console.log(err);
});
app.listen(8080);
// 파일이름 : 016_session\app2_5.js
// 더 간단한 예제입니다. 일부러 다른 모듈들은 다 지웠어요.
// 개발자도구 > 콘솔에서 입력해야 하는 코드는 console.js에 입력해두었습니다.
// 3분 뒤에도 실행해보세요!(3분 뒤로 조정했습니다.)
// npm init --yes
// npm i jsonwebtoken express express-session
// npm i nodemon --save-dev
const express = require('express');
const session = require('express-session'); // 이렇게 생성하면! req.session이 생성이 됩니다!
const jwt = require('jsonwebtoken');
const jwtsecret = 'hello world';
const app = express();
app.get('/', (req, res, next) => {
res.send('hello jwt!!!')
})
// 비밀 게시판
app.get('/secret', isAuthorized, (req, res) => {
res.json({ "m" : "secret notice" })
})
// 일반 게시판
app.get('/readme', (req, res) => {
res.json({ "m" : "share notice" })
})
app.get('/jwt', (req, res) => {
//JWT 토큰 생성(id와 blog 주소를 담아서)
const newUserToken = jwt.sign({"임시id":"hello"}, jwtsecret,{
expiresIn : 60 * 3 // 60초 유효 토큰 test할 때에는 뒤에 값을 늘려주세요.
});
res.send(newUserToken);
})
function isAuthorized(req, res, next) {
if (typeof req.headers.authorization !== "undefined") {
let token = req.headers.authorization.split(" ")[1];
jwt.verify(token, jwtsecret, (err, encode)=>{
if(err) {
console.log(err)
return res.send('잘못된 접근!');
} else {
console.log(encode)
return next();
}
});
} else {
return res.send('잘못된 접근!');
}
}
app.use((req, res, next) => {
res.status(404).send('못찾음!');
});
app.use((err, req, res, next) => {
console.log('애러발생!');
console.log(err);
});
app.listen(8080);
// 파일이름 : 016_session\console.js
//콘솔창에서 입력 후 test() 함수를 실행하세요.
async function test() {
const res = await fetch('/secret', {
method:'GET',
headers:{
'Content-Type' : 'application/json',
'Authorization' : 'Bearer ' + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyLsnoTsi5xpZCI6ImhlbGxvIiwiaWF0IjoxNjM1NTc3MDk0LCJleHAiOjE2MzU1NzczOTR9.H-jNCxjJAHKg0lm-O-v_ZnbOhvlYqaQqi_p0Gqz9OxU'
},
})
const resText = await res.text()
console.log(resText)
}
파일이름 : 016_session\index.html
<!DOCTYPE html><html lang="en">
<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>Document</title>
</head>
<body>
<form action="/" method="post">
아이디 : <input name="id" type="text"><br>
패스워드 : <input name="pw" type="text"><br>
<button type="submit">로그인</button>
</form>
</body>
</html>
// 파일이름 : 016_session\secret.js
module.exports = {
secretKey : 'secret key', // 시크릿 키를 넣으세요. 생성해주는 프로그램 사용하셔도 좋습니다.
option : {
algorithm : "HS256", // 해싱 알고리즘
expiresIn : "1m", // 토큰 유효 기간(s, m, h, d)
issuer : "hojun" // 발행자
}
}