쿠키
- 데이터를 바로 주고받고 상태를 브라우저에 저장, 데이터를 옮기는 매개체
- 쿠키를 이용해 서버는 사용자의 브라우저에 데이터 입력가능 => 사용자에 관한 정보를 기억
- 브라우저가 서버로부터 응답으로 Set-Cookie 헤더를 받은 경우 해당데이터를 저장 한뒤 모든 요청에 포함하여 전송
네이버 메인페이지에 저장된 내 쿠키들을 확인할 수 있다. 만료일자와 어떤 도메인에서 생성되었는지도 확인할 수 있다.
쿠키만들어보기(내가만든 쿠키)
- 서버가 클라이언트(브라우저)의 요청(Req)을 수신할 떄, 서버는 응답(Res)과 함께 Set-Cookie라는 헤더를 함께 전송할 수 있다. 그 후 쿠키는 해당 서버에 의해 만들어진 응답과 함께 Cookie HTTP 헤더안에 포함되어 전달 받는다.
- 쿠키파서 미들웨어설정
const cookieParser = require("cookie-parser")
app.use(cookieParser())
- res.cookie()를 이용하여 쿠키할당
//쿠키 할당
app.get("/set-cookie", (req, res) => {
let expires = new Date();
expires.setMinutes(expires.getMinutes() + 60); // 만료 시간을 60분으로 설정합니다.
res.cookie('name', 'sparta', {
expires: expires
});
return res.status(200).end();
});
- /set-cookie 경로로 요청된 get요청에 응답하는 정보들이 Headers에 담겨있다 Set-Cookie 부분에 name=value 값으로 쿠키가 할당되어있다.
- 크롬 개발자 도구 - 애플리케이션 - 쿠키 탭에서 할당받은 쿠키의 이름과 값, 도메인 이름, 만료시간등등을 확인 할 수 있다
- 개발자 도구에서 쿠키 확인
- thunder client에서 get요청으로 생성된 쿠키 응답값 확인
생성한 쿠키에 접근하기
- 클라이언트는 서버에 요청(Req)을 보낼 때 자신이 보유하고 있는 쿠키를 자동으로 서버에 전달. 클라이언트가 전달하는 쿠키정보는 Request header에 포함되어 서버에 전달됨.
- 쿠키는 아래코드에 들어있습니다. req.headers는 클라이언트가 요청한 Request의 헤더를 의미함.
req.headers.cookie
전달된 쿠키출력하기
- 서버에 전달된 쿠키는 req.cookies로 접근할 수 있다
- 쿠키의 기본적인 형태는 name=value로 이루어져 있으며 req.cookies를 사용하여 { name : value } 객체형태로 변경되었다.
//전달된 쿠키출력
app.get("/get-cookie", (req, res) => {
// const cookie = req.headers.cookie;
const cookies = req.cookies //cookieparser 미들웨어를 적용했기때문에 req.cookieparser 사용가능
console.log(cookies); // { name: ystar }
console.log(typeof (cookies)); // object
return res.status(200).json({ cookies }); //{cookies : cookies}
{
"cookies": {
"name": "ystar"
}
}
});
- 쿠키정보가 들어있는 요청(Req) 헤더, 쿠키의 기본적인 정보들이 들어있다.
세션
- 쿠키의 경우 서버를 재시작하거나 새로고침 하더라도 로그인이 유지됨 => 서버의 입장에서는 위험한 상황, 쿠키가 조작되거나 노출되는 경우 보안적인 문제 발생.
- 쿠키에는 사용자를 구분할 수 있는 정보를 넣어줌으로써 사용자의 특정 정보만 반환
- 세션은 데이터를 서버에만 저장함
- 간단하게, 서버에 저장된 데이터를 확인할 수 있는 열쇠라고 생각하면 된다.
- 쿠키를 사용한 서버보다 서버에 부하가 더 걸린다 사용자 ↑ 데이터 ↑ (사용자가 많아 질수록 저장되는 데이터도 증가)
- 세션에 서버부하를 보완하기 위해 cashe DB인 Redis라는 DB를 사용하여 개발
- 세션 data는 서버에 저장되고 데이터마다 고유한 ID가 생성됨, 세션 ID를 이용해 쿠키를 사용함.
세션 생성
//사용자의 정보를 저장할 자물쇠(데이터를 저장하는 부분)
let session = {}//key - value
app.get('/set-session', (req, res) => {
const name = "kim" //세션에 저장할 데이터
console.log(name) //kim
const uniqueInt = Date.now() //할당할 열쇠
console.log(uniqueInt) //1681922084252
//kim이라는 문자열이 session[uniqueInt]에 저장됨
session[uniqueInt] = name //세션에 데이터 저장
//1681922084252 : kim
res.cookie("sessionKey", uniqueInt)
res.status(200).end()
})
세션 확인
- 할당된 sessionKey - value 값 반환
세션 받아오기
- 생성된 세션을 sessionkey에 받아옴
- 변수 name에 할당
app.get('/get-session', function (req, res, next) {
const { sessionkey } = req.cookies;
console.log(sessionkey) //1681922084252
const name = session[sessionkey];
console.log(name)
return res.status(200).json({ name }); // name: kim
});
JWT
- JSON형태의 데이터를 안전하게 교환하여 사용가능
- 인터넷 표준으로서 자리잡은 규격
- 여러가지 암호화 알고리즘 사용가능
- header.payload.signature의 형식으로 3가지 데이터를 포함함
JWT형태
- 머리.가슴.배와 같은 형태를 가짐
- header(머리): signature(배)에서 어떤 암호화를 사용하여 생성된 데이터인지 표현함
- payload(가슴): 개발자가 원하는 실질적인 데이터를 저장
- signature(배): 해당 토큰이 변조되지않은 정상적인 토큰인지 확인할 수 있게 도와줌
- JWT는 비밀 키를 모르더라도 복호화(Decode)가 가능함
- 민감한 정보는 담지않아야함
- 모든언어에서 사용가능.
- 쿠키/세션과 차이점: 쿠키/세션은 데이터를 교환하는 방식, JWT는 데이터를 표현하는 방식
- 서버에 데이터를 저장하지 않기때문에 서버를 stateless(무상태)로 관리 할 수 있음 서버가 죽었다 살아나도 똑같은 동작을 수행함
JWT사용하기
npm install jsonwebtoken
JWT생성
//jwt 생성
const jwt = require("jsonwebtoken")
//jwt로 만들 데이터
const payloadData = {
myPayloadData: 1234
}
//const 변수명 = jwt.sign(jwt로 만들 데이터, 어떤 비밀키로만들지, )
const token = jwt.sign(payloadData, "mysecretkey")
console.log(token)
//header.payload.signature
//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJteVBheWxvYWREYXRhIjoxMjM0LCJpYXQiOjE2ODE4OTc2NDF9.IJ1Osy07KiOgvFJr3dTz4wp33ZoqxH-VZqct0aYlsL0
jwt.io에서 데이터 인코딩 디코딩
키 검증
payload데이터 복호화 .decode()
//jwt payload데이터 복호화
const decodedValue = jwt.decode(token)
console.log("복호화한 토큰입니다", decodedValue)
//복호화한 토큰입니다 { myPayloadData: 1234, iat: 1681924560 }
사용한 비밀키가 일치하는지 검증 .verify()
//jwt를 만들었을때 ,사용한 비밀키가 일치하는지 검증
const decodedValueByVerify = jwt.verify(token, "mysecretkey")
console.log("decodedValueByVerify :", decodedValueByVerify)
//decodedValueByVerify : { myPayloadData: 1234, iat: 1681924560 }
JWT없이 로그인 API작성하기
- 사용자의 정보가 'kim' 이라는 이름에 user 객체를 할당함
- 쿠키의 속성이나 만료시간을 클라이언트가 수정가능
- 쿠키의 위변조 여부확인 x
app.post('/login', function (req, res, next) {
const user = { // 사용자 정보
userId: 203, // 사용자의 고유 아이디 (Primary key)
email: "ystar@gmail.com", // 사용자의 이메일
name: "kys", // 사용자의 이름
}
res.cookie('kim', user); // kim 라는 이름을 가진 쿠키에 user 객체를 할당합니다.
return res.status(200).end();
});
JWT사용하여 로그인 API작성하기
- 사용자 정보를 payload에 저장한 jwt를 kim이름을 가진 쿠키에 할당
- jwt를 생성할때 위변조 여부를 확인할 수 있는 비밀키 사용
- 쿠키의 만료시간과 별개로 jwt의 만료시간 설정
const express = require('express');
const JWT = require("jsonwebtoken");
const app = express();
app.post('/login', async (req, res) => {
// 사용자 정보
const user = {
userId: 203,
email: "ystar5008@gmail.com",
name: "kys",
}
// 사용자 정보를 JWT로 생성
const userJWT = await JWT.sign(user, // user 변수의 데이터를 payload에 할당
"secretOrPrivateKey", // JWT의 비밀키를 secretOrPrivateKey라는 문자열로 할당
{ expiresIn: "1h" } // JWT의 인증 만료시간을 1시간으로 설정
);
// userJWT 변수를 kim 라는 이름을 가진 쿠키에 Bearer 토큰 형식으로 할당
res.cookie('kim', `Bearer ${userJWT}`);
return res.status(200).end();
});
JWT 사용처
- 암호화된 데이터는 클라이언트가 전달 받아 다양한 수단을 통해 저장하여 api서버에 요청을 할때 서버가 요구하는 HTTP인증양식에 맞게 보내주어 인증시도.
- 회원가입: 회원권 구매
- 로그인: 회원권으로 놀이공원 입장
- 로그인 확인: 놀이기구 탑승 전마다 유효한 회원권인지 확인
- 내 정보 조회: 내 회원권이 목에 잘 걸려 있는지 확인하고, 내 이름과 사진, 바코드 확인