로그인(인증) 세션 만료
먼저 인증과 인가에 대해 알아보자.
- 인증 (= 로그인)
Authentication
로그인 왜 필요한가? 로그인을 통해 가입된 유저인지를 확인 -> 특정 기능 사용 가능
쇼핑몰에서 상품을 볼 때는 로그인 필요X (단순히 데이터를 조회하는 용도, 크리티컬한 데이터가 아닌 공개적인 데이터)
쇼핑몰에서 장바구니 담을 때 로그인 필요O
쇼핑몰 상품 구매 시 로그인 필요O
마이 페이지 로그인 필요O
...
- 인가
Authorization 권한 , 허가 부여
ex. 같은 사이트 내에 관리자/고객에 따라 접근할 수 있는 페이지가 다름
인증 👉 관리자든 고객이든 인증을 통해 사이트에 가입된 사용자라는 것을 증명하는 것
인가 👉인증 후에 로그인한 사용자가 해당 페이지에 접근 권한이 있는가를 확인하는 것
서버가 클라이언트 인증을 확인하는 방법
쿠키 vs 세션 vs JWT
- 쿠키
1) 로그인하면 -> 서버가 쿠키를 굽는다. (쿠키 생성)
2) 사용자 <-> 서버가 쿠키를 핑퐁
장점 : 서버가 저장 X => 서버 저장공간 절약, Stateless(=> RESTful)
단점 : 보안 취약
- 세션
Cookie에 중요한 정보를 담지말고, 중요한 정보는 서버에 저장하자. 그 정보가 어딨는지 주소만 적어서 Cookie에 담자.
쿠키에 넣어서 보내기엔 너무 중요한 내용은 서버가 가진 금고(Session)에 넣어두고 그 금고번호(Session ID)만 쿠키에 넣어 통신한다.
1) 로그인하면 -> 서버가 금고를 만들어서 정보를 저장하고 그 금고에 번호를 부여한다.
2) 사용자 <-> 서버가 번호만 가지고 대화(통신)
장점 : 보안 비교적 개선
단점 : 서버가 저장 O => 서버가 저장공간을 차지, Stateless X
세션은 상태를 의미하는데 주로 웹개발에서는 로그인이 되어있는 상태를 말한다.
쿠키와 세션의 단점을 보완해서 나온 것이 JWT이다.
- JWT(JSON Web Token)
개념 : JSON 형태의 데이터를 안전하게 전송하기 위한 웹에서 사용하는 토큰
= 토큰을 가진 사용자가 증명을 하기위한 수단
cf. 토큰은 (인증용) 입장 가능한 유저인지 확인 / (인가용) 관리자 권한&일반 유저 권한 구분을 목적으로 사용한다.
장점 :
- 보안에 강함 <= 암호화가 되어있다.
- HTTP 특징을 잘 따른다. = Stateless하다. <= 서버가 상태를 저장하지 않는다.
- 서버에 부담을 줄여줄 수 있다.
+ 토큰을 발행하는 서버를 따로 만들어 줄 수도 있다.
구조 (jwt.io 참고)
- 헤더(Header) : 토큰을 암호화하는데 사용한 알고리즘, 토큰의 형태(jwt)
- 페이로드(Payload, 내용) : 사용자 정보 담겨있다(ex. 이름, 주소, 핸드폰, ... 원하는 정보 담으면 되지만 비밀번호를 담는 경우는 잘 없긴함)
- 서명(Signature) : 만약 페이로드 값이 바뀌면 이 서명값이 통째로 바뀌기때문에 JWT를 믿고 쓸 수 있다.
JWT 인증/인가 절차

JWT 사용하기 위한 node.js에 설치 명령어 (jwt 설치 및 사용방법)
npm i jsonwebtoken
token 생성 (= token 서명을 했다.)
👉 jwt.sign(payload, secretOrPrivateKey, [options, callback])
var jwt = require('jsonwebtoken'); //jwt 모듈 소환
//토큰 생성
var token = jwt.sign({ foo: 'bar' }, 'shhhhh'); //jwt.sign(페이로드, 나만의 암호키) + 알고리즘은 SHA256
console.log(token);
// console.log(token);의 출력값
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MDM0Nzc0MzV9.Fe_3Xd1UIkA2gMoXzjhfd9m1aN-ugVaqY_8tnqdHsTA
출력값을 보면 jwt의 구조를 알 수 있다.
XXXX.YYYY.ZZZZ 👉 header.payload.signature
jwt.io에서 토큰 해독을 통해 ".(dot)"을 기준으로 각 영역에 담긴 정보를 알 수 있다.

검증 (검증 성공하면 페이로드 값을 확인할 수 있음) 👉 jwt.verify(token, secretOrPublicKey, [options, callback])
let decoded = jwt.verify(token, "shhhhh");
console.log(decoded); //{ foo: 'bar', iat: 1703477435 }
console.log(decoded.foo); //bar
.env (environment: 환경 변수 즉, '설정 값')
개념 :
개발을 하다 포트넘버, 데이터베이스 계정, 암호키, ... 등 외부에 유출되면 안되는 중요한 환경 변수
, 깃허브에 올라가면 안되는 값을 따로 관리하기위한 파일
파일 확장자가 .env
.env 파일은 환경 변수 파일 -> 프로젝트 최상위 패키지에 존재해야한다.
dotenv 모듈 설치 명령어 & 사용법 (dotenv)
npm i dotenv
cookie에 jwt 담아서 응답하기
// 로그인
router.post(
"/login",
[
body("email").notEmpty().isEmail().withMessage("이메일 확인 필요"),
body("password").notEmpty().isString().withMessage("패스워드 확인 필요"),
validate,
],
(req, res) => {
const { email, password } = req.body;
let sql = `SELECT * FROM users WHERE email = ?`;
conn.query(sql, email, function (err, results) {
if (err) {
console.log(err);
return res.status(400).end();
}
let loginUser = results[0];
if (loginUser && loginUser.password == password) {
//token 발급
const token = jwt.sign(
{
email: loginUser.email,
name: loginUser.name,
},
process.env.PRIVATE_KEY
);
//쿠키에 토큰 담아 보내는 방법
res.cookie("token", token);
res.status(200).json({
message: `${loginUser.name}님 로그인 되었습니다.`,
token: token,
});
} else {
res.status(403).json({
message: "이메일 또는 비밀번호가 틀렸습니다.",
});
}
});
}
);
로그인 API에서 로그인 성공했을 때 token을 생성하고 res.cookie()를 통해 cookie에 토큰을 담았다.
//token 발급
const token = jwt.sign(
{
email: loginUser.email,
name: loginUser.name,
},
process.env.PRIVATE_KEY
);
//쿠키에 토큰 담아 보내는 방법
res.cookie("token", token);
클라이언트가 로그인 요청을 보냄 -> 서버가 DB에서 데이터를 확인 -> 토큰 발행 -> 로그인 성공 응답 + cookie에 토큰 담아 보내기

위의 이미지에서 HttpOnly와 Secure를 볼 수 있다. 이 두가지는 보안상에서 중요한 역할을 한다.
Secure는 http, https 환경 중 어떤 환경에서 보낼 것인지를 물어보는 것이다.
HTTP
ex. http://localhost:3000
HTTPS
ex. https://www.naver.com/
S는 Secure를 의미하고 http를 암호화해서 보낸다는 말이다.
HttpOnly(= 프론트엔드가 아니라 API 호출"만" 허락할거니?) : XXS 공격(프론트엔드 공격 : 웹 브라우저로 js에 접근해 공격하는 것)
false -> 프론트엔드 즉, 화면단에서 공격이 들어오면 공격 당할 수 있다.
true => 프론트엔드 신경안쓰고 Http API로만 쿠키 접근하게 한다.
httpOnly를 true로 바꾸기
res.cookie("token", token, { httpOnly: true });

JWT 유효기간 설정
JWT의 유효기간을 설정하지 X = 영원히 유효한 토큰 = 영원히 로그인 세션이 만료 X (계속 로그인 상태)
그래서 JWT의 유효기간을 설정해줘야한다.
const token = jwt.sign(
{
email: loginUser.email,
name: loginUser.name,
},
process.env.PRIVATE_KEY,
{
expiresIn: "5m",
issuer: "yunss", //issuer: 토큰 생성한 사람
}
);
토큰 값을 복사해서

jwt.io에서 유효기간이 설정된 것을 확인할 수 있다.

'Node.js' 카테고리의 다른 글
| 12/22 express.js 유효성 검사 (0) | 2023.12.25 |
|---|---|
| 12/21 DB 모듈화, DB연동 후 회원 API/코드, 채널 API/코드 수정 (0) | 2023.12.24 |
| 12/14~15 (0) | 2023.12.18 |
| 12/13 express.js ==과 ===의 차이, 예외처리 고도화 (1) | 2023.12.18 |
| 12/11 express.js postman, express.js에서 사용되는 메소드들, 속성들 (0) | 2023.12.14 |