프론트의 세션 스토리지는 로컬 스토리지와 엮어서 자료를 찾아보면 쉽다. 간단하게 브라우저를 닫았을 때 남아있을 것인가, 사라질 것인가의 차이라고 볼 수 있다. 이들과 엮이는 쿠키의 경우 보통 서버에서 클라이언트에게 쿠키를 발급할텐데, jwt는 이 쿠키에 담을 수도 있고 아니면 직접 전달될 수도 있다. https의 사례도 있겠으나 보안상 큰 장점을 갖지는 않는데, 두 경우의 차이점을 알아두면 좋다.
const userToken = req.headers["authorization"]?.split(" ")[1];
bearer는 기술적인 의미보다는 국제 표준이라고 생각하면 된다.
res.status(403).json({
result: "forbidden-approach",
reason: "로그인한 유저만 사용할 수 있는 서비스입니다.",
});
먼저 throw/return의 차이를 알아 둘 필요가 있는데 return의 동기적 실행은 '반환값'이 '실제적 결과'와 뚜렷하게 구분되고 함수를 끝내기(end)위해 쓰이는 반면, throw 비동기적 실행은 반환값이나 에러 객체가 resolve 할 Promise 객체를 물고 늘어지면서 성공/실패를 암시하며, 현 함수에서 나가기(quit)위해 실행 다. https://stackoverflow.com/questions/56910169/difference-between-return-error-and-throw-error 참조
위의 예시에서 에러 처리를 "loginRequired" middleware에서 떼어내 error handler에 정의하는 방법도 있다. 이 때 trigger가 중요한 역할을 하는데, 가령 error.message가 로그인과 연관된 '특정한 주문'처럼 기능해서 같은 403 상태에서도 특정 result/reason 내용을 갖는 에러를 전달하는 것이다.
db 스키마 관련 정보가 프론트에 전달된다면 보안에 결점이 생길 수 밖에 없다. 게다가 불필요한 정보 전달이 쌓이면 성능 저하도 생길 수 있다. 가장 걱정되는 점은 db 스키마에 변화가 생겼을 때 프론트가 이를 능동적으로 반영하지 못하는 경우가 생길 수 있다는 점이다. 이를 의존성이 생긴다고 정의할 수 있다.
categoryRouter.patch("/:category/add", loginRequired, adminGuard, async (req, res, next) => { ... }
categoryRouter.patch("/:category/remove", loginRequired, adminGuard, async (req, res, next) => { ... }
단적으로 post(api/categories/:category/:product)와 같은 경로를 생각해볼 수 있겠다. 혹은 product 정보를 body에 싣거나. 더 중요한 것은 patch method는 product를 삽입하거나 빼는 작업이 아니라 category 자체의 수정에 가깝게 다가온다는 점이다. https://inpa.tistory.com/entry/EXPRESS-%F0%9F%93%9A-reqparams-reqquery-reqbody-%F0%9F%A4%94-%EC%A0%95%EB%A6%AC 참조