Clone Something/Netflix -Lama

REACT. Node.js Netflix App | Netflix 클론 코딩 (5)

(*ᴗ͈ˬᴗ͈)ꕤ*.゚ 2022. 6. 22. 14:33

1. LOGIN

 auth.js 

router.post("/login", async (req, res) => {
  try {
  
  } catch {
  
  }
});

로그인 할 수 있게 "/login" 경로를 지정해주고 async, await로 비동기 처리 하고 try,catch 하자!

 

가독성을 위해 try, catch만 따로 빼서 보려고 했는데 가독성이 더 안좋아진 것 같다

try {
  const user = await User.findOne({ email: req.body.email });
  !user && res.status(401).json("Wrong password or username!");
  res.status(200).json();
} catch (err) {
  res.status(500).json(err);
}

1) email로 user을 찾자

2) user이 없으면(false이면) json에 이걸 출력하가

3) 자체 에러가 없으면 status(200), 자체 에러가 있으면 status(500)

 

암호화의 반대, decrypt를 하자 (그래야 비밀번호가 맞는지 안맞는지 확인이 가능하다)

// decrypt( <-> encrypt)
const bytes = CryptoJS.AES.decrypt(user.password, process.env.SECRET_KEY);
const originalPassword = bytes.toString(CryptoJS.enc.Utf8);

originalPassword !== req.body.password &&
  res.status(401).json("Wrong password or username!");

 

마지막으로 json으로 불러 올 때, 암호를 빼고 불러오자(보안보안)

const { password, ...info } = user._doc;
res.status(200).json(info);

 

전체를 보면 다음과 같다

router.post("/login", async (req, res) => {
  try {
    const user = await User.findOne({ email: req.body.email });
    !user && res.status(401).json("Wrong password or username!");

    // decrypt( <-> encrypt)
    const bytes = CryptoJS.AES.decrypt(user.password, process.env.SECRET_KEY);
    const originalPassword = bytes.toString(CryptoJS.enc.Utf8);

    originalPassword !== req.body.password &&
      res.status(401).json("Wrong password or username!");

    const { password, ...info } = user._doc;

    res.status(200).json(info);
  } catch (err) {
    res.status(500).json(err);
  }
});

 

2. JWT(존맛탱 아니... JSON WEB TOKEN)

 auth.js 

jsonwebtoken을 호출하고, catch안에 accessToken를 설정하자!

 

accessToken 안에는 id, isAdmin, SECRET_KEY, 만료일이 들어간다

const jwt = require("jsonwebtoken");

catch {
const accessToken = jwt.sign(
  { id: user._id, isAdmin: user.isAdmin },
  process.env.SECRET_KEY,
  { expiresIn: "5d" }
);

const { password, ...info } = user._doc;

res.status(200).json({ ...info, accessToken });
}

postman에서 send를 누르면, 이전과 다르게 accessToken도 같이 불러와진다

 

3. REST API User CRUD Operations(Update)

거창한 제목을 썼지만 사실 별거 없

회원정보를 어떻게 수정할까?를 의미한다

 

 verifyToken.js 

 

기본구조

const jwt = require("jsonwebtoken");

function verify(req, res, next) {}

module.exports = verify;

 

authHeader이 있다면 accessToken을 비교,

authHeader이 없다면 "You are not authenticated"라 출력

 

accessToken을 사용가능한 Token이라면 next()를 통해 판단을 다음으로 유보하고

accseeToken을 사용가능하지 않는 Token이라면, "Token is not valid!"라 한다

const jwt = require("jsonwebtoken");

function verify(req, res, next) {
  const authHeader = req.headers.token;
  if (authHeader) {
    const token = authHeader.split(" ")[1];

    jwt.verify(token, process.env.SECRET_KEY, (err, user) => {
      if (err) res.status(403).json("Token is not valid!");
      req.user = user;
      next();
    });
  } else {
    return res.status(401).json("You are not authenticated");
  }
}

module.exports = verify;

 

 /routes/user.js 

 

호출할거 호출하고 한 기본구성이다

const router = require("express").Router();
const User = require("../models/User");
const CryptoJS = require("crypto-js");
const verify = require("../verifyToken");

// UPDATE

module.exports = router;

 

'// UPDATE' 안을 채워줄 것이다

경로는 /:id, verify를 스쳐지나감(거기서 next()한다)

 

(req.user.id)와 (req.params.id) or (req.user.isAdmin)이 같다면 올바른 일을 수행하고,

아니면 403을 띄운다

// UPDATE
router.put("/:id", verify, async (req, res) => {
  if (req.user.id === req.params.id || req.user.isAdmin) {
    // 올바른 일 수행
  } else {
    res.status(403).json("You can update only your account!");
  }
});

 

아래는 올바른 일을 수행할 때의 코드이다

// 올바른 일 수행
if (req.body.password) {
  req.body.password = CryptoJS.AES.encrypt(
    req.body.password,
    process.env.SECRET_KEY
  ).toString();
}
try {
  const updatedUser = await User.findByIdAndUpdate(
    req.params.id,
    {$set: req.body,}, {new: true,}
  );
  res.status(200).json(updatedUser);
} catch (err) {
  res.status(500).json(err);
}

{$set: req.body} -> 업데이트 해준다

{new: true} -> 새로운 내용으로 업데이트