- jsonwebtoken 패키지 설치
- 발급 sign() 메서드 와 검증 verify() 메서드 를 이용해서 서버<->클라 간 토큰 발급 및 검증
1. 패키지 설치
npm i cookie-parser jsonwebtoken
2. 서버) 로그인 요청에 대해서 토큰 생성 (유저확인->토큰생성->응답)
// 로그인 처리 (토큰 생성)
const signIn = async (req, res) => {
// 로그인 시도하는 유저 정보
const { userId, userPw } = req.body;
// .. ID/PW 확인 로직
// 생략
// 회원일때
if (isMember) {
// JWT 발급
// sign({토큰의 내용}, 토큰의 비밀 키, {토큰의 설정}) , issuer 는 발급자임.
const token = jwt.sign({ id: result[0].userid }, JWT_SECRET, { expiresIn: '10m', issuer: 'NodeServer' });
console.log('컨트롤러 >> ', token);
// 쿠키에 jwt를 담아서 보내보자
res.cookie('jwtCookie', token, {
maxAge: 30 * 60000,
httpOnly: true,
});
// 요청 본문 (JWT를 쿠키로 보내도 되지만 요청 본문으로도 보낼 수 있다.)
res.send({
success: true,
msg: '로그인 성공, 토큰 발행되었음',
// token,
});
} else {
res.send({
success: false,
msg: '로그인 실패',
});
}
};
두가지 방법으로 토큰을 클라이언트에게 전달해봄
- 응답 헤더(header)에 토큰이 담긴 쿠키 정보를 포함
- 응답 본문(body)에 토큰을 포함
3. 브라우저) 서버에게 토큰 검증요청
각각 방법으로 JWT를 전달 받았을때 클라이언트에서 처리방법도 다름.
- 쿠키로 받았을때 : 다른 요청을 보낼 때 브라우저 쿠키에 있는 JWT를 자동으로 요청에 포함시켜서 보냄.
- 본문로 받았을때 : 다른 요청을 보낼 때 헤더의 authorization에 JWT를 포함시켜서 요청
// 로그인 요청
axios({
method: 'post',
url: '/user/signin',
data: {
userId,
userPw,
},
}).then((response) => {
//// 응답 쿠키로 JWT를 발급 받은 후
// 서버에게 토큰 검증요청
axios.get('/tokenTest')
.then((res) => { console.log(res.data) })
.catch((err) => { console.log(err) })
//// 응답 본문으로 JWT를 발급 받은 후
// 서버에게 토큰 검증요청
const token = response.data.token;
axios.get('/tokenTest', { headers: { authorization: token }, })
.then((res) => { console.log(res.data) })
.catch((err) => { console.log(err) })
});
4. 서버에서 토큰 검증 ('/tokenTest')
라우터
// 토큰 확인 라우터
router.get('/tokenTest', verifyToken, controller.tokenTest);
미들웨어 (verifyToken)
const jwt = require('jsonwebtoken');
const JWT_SECRET = 'jwtSecret';
// 토큰 검증 미들웨어
// 요청 헤더에서 토큰값을 확인 한후 비밀키로 검증한다.
exports.verifyToken = (req, res, next) => {
try {
// res.locals 에 저장한 내용은 다음 미들웨어로 전달된다.
// verify(요청헤더에 저장된 토큰 , 비밀키)
console.log('req.headers.authorization>>>>', req.headers.authorization);
// res.locals.decoded에 저장하면 미들웨어 다음 컨트롤러에서 이 값을 사용할 수 있음.
res.locals.decoded = jwt.verify(req.headers.authorization, JWT_SECRET);
console.log('middleWare >> ', res.locals.decoded);
return next();
} catch (err) {
// 여기서 검증 실패시 처리
if (err.name === 'TokenExpiredError') {
return res.status(419).json({
msg: '토큰 만료',
});
}
return res.status(401).json({
msg: '유효하지 않는 토큰',
});
}
};
미들웨어를 거친 다음 컨트롤러에서 로직수행(tokenTest)
- 응답으로 검증된 토큰을 리턴하는걸로 대체함
const tokenTest = (req, res) => {
res.send(res.locals.decoded);
// exp: 1697541810 // 토큰의 만료 시간
// iat: 1697541210 // 토큰이 발급된 시간
// id: "tgkim" // 토큰 발급시 설정했던 유저의 id
// iss: "NodeServer" // 토큰을 발급한 주체
};
5. 브라우저 쿠키에서 확인한 JWT
값이 헤더.페이로드.서명 형식으로 저장된다.
- 헤더(HEADER): 토큰 종류와 해시 알고리즘 정보가 들어 있습니다.
- 페이로드(PAYLOAD): 토큰의 내용물이 인코딩된 부분입니다.
- 시그니처(SIGNATURE): 일련의 문자열로, 시그니처를 통해 토큰이 변조되었는지 여부를 확인할 수 있습니다.
토큰 위변조는 서버에서 검증을 진행하면 되지만... 검증된 JWT가 있는 쿠키를 다른 브라우저로 복사 붙여넣기하면 문제없는 JWT를 다른 사람이 사용할 수 있을것 같다.
>> IP를 사용해보기
1. JWT 내에 추가 정보 포함: JWT에 IP 주소와 사용자 에이전트 정보를 포함할 수 있습니다. 예를 들어, 사용자가 로그인할 때 현재 IP 주소와 사용자 에이전트 정보를 JWT에 추가합니다.
2. IP 주소 및 사용자 에이전트 비교: 각 요청을 처리하기 전에, JWT에 포함된 IP 주소 및 사용자 에이전트 정보를 현재 요청의 정보와 비교합니다. 일치하지 않는 경우, 보안 이슈로 간주할 수 있습니다.
3. 처리 또는 거부: IP 주소 또는 사용자 에이전트가 일치하지 않는 경우, 해당 요청을 거부하거나 추가 보안 검증을 요구
'Nodejs' 카테고리의 다른 글
[Fastify] Fastify - Node.js 웹 프레임워크 (1) | 2024.02.07 |
---|---|
[Nodejs] 쿠키와 세션 인증 그리고 JWT (0) | 2023.10.21 |
[nodejs] Express-session (0) | 2023.10.16 |
[Nodejs] Express에서 redis를 session storage로 사용 (0) | 2023.10.15 |
[Nodejs] 싱글 스레드 (1) | 2023.10.04 |