📝

20. session

📝
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" // 발행자     } }