글을 작성하거나 삭제하는 것 같은 권한이 필요한 컨텐츠와 로그인 유무등을 체크하기 위해 구현
이를 구현하기 위해서 클라이언트 쿠키에 저장된 토큰과 서버 데이터 베이스에 저장된 토큰이 일치하는지 확인합니다.
var token = jwt.sign(user._id.toHexString(), "hasVisited");
user._id + "hasVisited" = token 조합으로 인코드 되어 있는 토큰의 디코드를 통해 유저의 아이디를 추출해서 해당 아이디를 가진 유저의 DB에 같은 토큰이 존재하지는 확인하면 Authentication의 기능을 구현할 수 있습니다.
위와 같은 로직 위해서는 쿠키에 저장된 토큰을 서버에서 가져와 복호화를 진행합니다.
복호화를 통해 추출된 유저의 아이디로 데이터베이스안에 해당 아이디가 있는지 확인 후 있다면 쿠키에서 받아온 토큰을 동일하게 가지고 있는지 확인합니다.
app.get("/api/users/auth", auth, (req, res) => { ... });
auth는 callback 함수를 실행하기 전에 중간에서 먼저 실행하는 역할을 하는데 이때 위에서 언급한 디코드 과정을 진행하며 디코드 구현을 위해 루트 디렉토리에서 middleware 폴더 > auth.js 를 생성합니다.
const { User } = require("../models/User");
let auth = (req, res, next) => {
// 클라이언트 쿠키에서 토큰 가져오기
let token = req.cookies.hasVisited;
// 토큰을 복호화 한후 일치하는 유저 찾기
User.findByToken()
};
module.exports = { auth };
userSchema.statics.findByToken = function (token, cb) {
var user = this;
// 토큰을 decode 한다.
jwt.verify(token, "hasVisited", function (err, decoded) {
// 유저 아이디를 이용해 유저를 찾은 다음에
// 클라이언트에서 가져온 token과 DB에 보관된 토큰이 일치하는지 확인
user.findOne({ _id: decoded, token: token }, function (err, user) {
if (err) return cb(err);
cb(null, user);
});
});
};
코드 해석
유저의 토큰을 디코드하는 findByToken 생성
jwt.verify()을 통해 디코드를 실행
디코드된 유저의 아이디로 유저를 찾음(user.findOne)
const { User } = require("../models/User");
let auth = (req, res, next) => {
// 클라이언트 쿠키에서 토큰 가져오기
let token = req.cookies.hasVisited;
// 토큰을 복호화 한후 일치하는 유저 찾기
User.findByToken(token, (err, user) => {
if(err) throw err;
if(!user) return res.json({isAuth: false, error: true})
req.token = token;
req.user = user;
next();
})
};
module.exports = { auth };
코드 해석
생성한 findByToken으로 유저를 찾고 유저가 있다면 유저의 토큰과 아이디에 값을 넣어주고
next()를 통해 미들웨어를 나갈 수 있게합니다.
app.get("/api/users/auth", auth, (req, res) => {
res.status(200).json({
_id: req.user._id,
email: req.user.email,
name: req.user.name,
title: req.user.title,
isAuth: true,
});
});
해당 코드에 도달하면 auth 미들웨어를 통과해 왔다는 의미로 Authentication이 true가 되니 200 코드를 넘겨주고 json 형태로 원하는 값을 넘겨줍니다.
권한이 true로 잘넘어오는지 포스트맨에서 확인