여기서 JWT는 욕아님
인증을 위한 JWT(JSON Web Token)
밑에의 페이지에서 소스의 정보를 확인할 수 있음
NodeBird가 아닌 다른 클라이언트가 데이터를 가져가게 하려면 인증 과정이 필요함
- JWT(JSON Web Token)을 사용함
- 헤더.페이로드.시그니처로 구성됨
- 헤더: 토큰 종류와 해시 알고리즘 정보가 들어있음
- 페이로드: 토큰의 내용물이 인코딩된 부분
- 시그니처: 일련의 문자열로, 시그니처를 통해 토큰이 변조되었는지 여부 확인
- 시그니처는 JWT 비밀키로 만들어지고, 비밀키가 노출되면 토큰 위조 가능
JWT 사용 시 주의점
JWT에 민감한 내용을 넣으면 안 됨
- 페이로드 내용 볼 수 있음
- 그럼에도 사용하는 이유는 토큰 변조가 불가능하고, 내용물이 들어있기 때문
- 내용물이 들어있으므로 데이터베이스 조회를 하지 않을 수 있음(데이터베이스 조회는 비용이 큰 작업)
- 노출되어도 좋은 정보만 넣어야 함
- 용량이 커서 요청 시 데이터 양이 증가한다는 단점이 있음
- 위에 코드로 보면 ey~FQ까지는 볼 수 있어도 . 뒤에 나오는 비밀키는 유출되면 안됨
노드에서 JWT 사용하기
JWT 모듈 설치
- npm i jsonwebtoken
- JWT 비밀키 .env에 저장
- JWT 토큰을 검사하는 verifyToken 미들웨어 작성
- jwt.verify 메서드로 검사 가능(두 번째 인수가 JWT 비밀키)
- JWT 토큰은 req.headers.authorization에 들어 있음
- 만료된 JWT 토큰인 경우 419 에러 발생
- 유효하지 않은 토큰인 경우 401에러 발생
- req.decoded에 페이로드를 넣어 다음 미들웨어에서 쓸 수 있게 함
const jwt = require('jsonwebtoken');
exports.isLoggedIn = (req, res, next) => {
if (req.isAuthenticated()) {
next();
} else {
res.status(403).send('로그인 필요');
}
};
exports.isNotLoggedIn = (req, res, next) => {
if (!req.isAuthenticated()) {
next();
} else {
res.redirect('/');
}
};
exports.verifyToken = (req, res, next) => {
try {
req.decoded = jwt.verify(req.headers.authorization, process.env.JWT_SECRET);
return next();
} catch (error) {
if (error.name === 'TokenExpiredError') { // 유효기간 초과
return res.status(419).json({
code: 419,
message: '토큰이 만료되었습니다',
});
}
return res.status(401).json({
code: 401,
message: '유효하지 않은 토큰입니다',
});
}
};
JWT 토큰 발급 라우터 만들기
routes/v1.js 작성
- 버전 1이라는 뜻의 v1.js
- 한 번 버전이 정해진 후에는 라우터를 함부로 수정하면 안 됨
- 다른 사람이 기존 API를 쓰고 있기 때문(그 사람에게 영향이 감)
- 수정 사항이 생기면 버전을 올려야 함
- POST /token에서 JWT 토큰 발급
- 먼저 도메인 검사 후 등록된 도메인이면 jwt.sign 메서드로 JWT 토큰 발급
- 첫 번째 인수로 페이로드를 넣고, 두 번째 인수는 JWT 비밀키, 세 번째 인수로 토큰 옵션(expiresIn은 만료 시간, issuer은 발급자)
- expiresIn은 1m(1분), 60 * 1000같은 밀리초 단위도 가능
- GET /test 라우터에서 토큰 인증 테스트 가능
- 라우터의 응답은 일정한 형식으로 해야 사용자들이 헷갈리지 않음
app.js에 라우터 연결
.
.
.
.
const dotenv = require('dotenv');
dotenv.config();
const v1 = require('./routes/v1');
const authRouter = require('./routes/auth');
.
.
.
app.use(passport.session());
app.use('/v1', v1);
app.use('/auth', authRouter);
.
.
.
JWT 토큰으로 로그인하기
세션 쿠키 발급 대신 JWT 토큰을 쿠키로 발급하면 됨
- Authenticate 메서드의 두 번째 인수로 옵션을 주면 세션 사용하지 않음
클라이언트에서 JWT를 사용하고 싶다면
- process.env.JWT_SECRET은 클라이언트에서 노출되면 안 됨
- RSA같은 양방향 비대칭 암호화 알고리즘을 사용해야 함
- JWT는 PEM 키를 사용해서 양방향 암호화를 하는 것을 지원함