어제 쿠키와 세션을 해서 그런지 토큰은 생각보다 수월하게 할 수 있었던 것 같았다. 물론, 그게 곧 Token 이 쉬웠다는 말은 아니다. 다만 우리가 스프린트를 진행하는데 있어서 전체적인 서버 플로우가 이해되다 보니 어찌저찌 잘 해낼 수 있는 것 같았다. 내일은 OAuth 인데 어찌저찌 잘 할 수 있을 것 같다.
[ 오늘의 TODO ]
코드 스테이츠) 토큰코드 스테이츠) Pair-Programming// im-sprint-auth-token패스트 캠퍼스) 인강 3개 이상 듣기 // optional생활) 물 1L 이상 마시기- 생활) 1시간 이상 걷기
// 걸을 시간 진짜 없다.. 개선) 페어 프로그래밍할 때도 혼자 있을 때처럼 침착하게 오류 대처하기

[ 오늘의 코드]
1. jwt.verify( )
우리가 배운 토큰 생성은 jwt 였다. require('jsonwebtoken') 을 통해서 jwt 패키지를 가져오고 서버에서 토큰알 받아들인 후, 해석하여 우리가 받은 토큰이 맞는 지를 확인한 후 맞다면 토큰 안에 있는 내용을 담아준다. jwt 는 첫 번째 인자로 클라이언트로부터 건너온 토큰, 두 번째 인자로 secret 혹은 public key 를 적고, 마지막 세 번째로 콜백 함수를 인자로 받을 수 있다. 여기서 마지막 인자인 콜백 함수는 옵션인데 사용한다면 전환한 데이터를 어떻게 사용할지 정의해줄 수 있다. 나와 페어 분은 그 방법과 더불어서 콜백을 사용하지 않고 사용해보는 두 가지 방법을 이용해봤다. 역시나 정상적으로 잘 작동했다.
jwt.verify(token, process.env.ACCESS_SECRET, async (err, data) => {
if (err) {
res.status(400).json({ data: null, message: "invalid access token" });
} else {
const userInfo = await Users.findOne({
where: { userId: data.userId },
});
if (!userInfo) {
res
.status(400)
.json({ data: null, message: "access token has been tempered" });
} else {
const { id, userId, email, createdAt, updatedAt } = userInfo;
const userInfoFromToken = { id, userId, email, createdAt, updatedAt };
res
.status(200)
.json({ data: { userInfo: userInfoFromToken }, message: "ok" });
}
}
});
// ! ---------------------- 다른 방법 ----------------------------
const data = jwt.verify(token, process.env.ACCESS_SECRET);
if (!data) {
res.status(400).json({ data: null, message: "invalid access token" });
} else {
const userInfo = await Users.findOne({
where: { userId: data.userId },
});
if (!userInfo) {
res
.status(400)
.json({ data: null, message: "access token has been tempered" });
} else {
const { id, userId, email, createdAt, updatedAt } = userInfo;
const userInfoFromToken = { id, userId, email, createdAt, updatedAt };
res
.status(200)
.json({ data: { userInfo: userInfoFromToken }, message: "ok" });
}
}
이렇게 작성할 때 주의해야 할 점은 어디에 async 를 달아줘야 하는 점이다. 데이터베이스에 요청을 하는 작업은 비동기로 이루어진다. 그렇기 때문에 데이터베이스를 가져올 때 비동기 처리를 해줘야 하는데 어느 포인트에서 비동기 처리를 해줘야하는지가 중요했다. verify 안에 콜백 함수로 사용하는 경우 그 안에 async 를 달고 데이터베이스에 해당 내용이 있는지 찾고자 할 때 await 를 넣어주었다.
2. jwt.sign ( )
jwt 를 사용할 때 access 토큰을 만드는 방법은 바로 jwt.sign( ) 이다. 첫 번째 인자로는 토큰의 payload 부분을 어떻게 작성해줄 것인지를 객체의 형태로 넣고 두 번째 인자로 secret 혹은 public key, 그 이후에 인자로 몇 가지 옵션이나 콜백함수를 넣을 수 있다. 내가 사용한 인자는 expiresIn 인자였다. 토큰의 유효 시간을 지정해주는 옵션이었다. 이 옵션을 사용한 이유는 access token 과 refresh token 의 사용을 구분하기 위함이었다. 서버에서 토큰을 만들 때 두 개를 만들어서 보내준다. 하나는 access token 으로 react state 등에 저장해서 사용하는 용도고 refresh token 은 쿠키에 저장해 만약 access token 이 expire 한다면 새롭게 토큰을 발급받기 위해 필요한 토큰이다. 그렇기에 access token 은 유효기간이 짧고, refresh token 은 유효기간이 길 수밖에 없다. (만약 권한을 전해주기 위한 용도로만 사용한다면 refresh token 은 필요로 하지 않는다)
const accessToken = jwt.sign(info, process.env.ACCESS_SECRET, {
expiresIn: "1m",
});
const refreshToken = jwt.sign(info, process.env.REFRESH_SECRET, {
expiresIn: "1h",
});
3. cookie-parser
어제 express-session 패키지를 배우면서 그럼 cookie-parser 패키지는 필요 없겠네 했는데 토큰 인증 방식을 사용할 때는 필요하다. 이 패키지가 필요한 이유는 request 요청에서 담긴 쿠키를 간편하게 가져올 수 있기 때문이다. 어제 공부했을 때 res.cookie 라는 메소드는 express 의 내장 메소드라고 배웠다. 그와 유사하게 cookie-parser 를 사용하면 req.cookie 를 사용할 수 있다. 이 메소드가 쿠키 값을 가져오는 역할을 한다. 토큰 인증 방식에서 refresh token 을 가져와 새로운 토큰을 발급해줘야 하는 경우, 이 메소드가 필요했다.
const refreshToken = req.cookies.refreshToken
'코드스테이츠 > 코드스테이츠 @ 개발 일지' 카테고리의 다른 글
[코드 스테이츠] 99일차, "프로젝트 팀 결성" (2) | 2021.10.26 |
---|---|
[코드 스테이츠] 96일차, "일시정지" (0) | 2021.10.23 |
[코드 스테이츠] 94일차, "인증 / 보안 - Cookie, Session" (0) | 2021.10.20 |
[코드 스테이츠] 93일차, "미리 예습하기" (0) | 2021.10.19 |
[코드 스테이츠] 92일차, "ORM" - 이후 평일 블로깅 스타일 바뀝니다. (0) | 2021.10.19 |